{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "gzsl_LisGAN using torch.ipynb",
      "provenance": [],
      "mount_file_id": "15wyErbgb2Jdh32iEGxJRWbD1CaRr54AY",
      "authorship_tag": "ABX9TyMOEEH4oAtjTOgVYA+wNDpq",
      "include_colab_link": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "accelerator": "GPU"
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/1995subhankar1995/LisGAN-using-torch/blob/master/gzsl_LisGAN_using_torch.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "uw7YONB_lFpZ",
        "colab_type": "code",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 54
        },
        "outputId": "0eecc304-b5bc-4450-d319-91ab6a25ca70"
      },
      "source": [
        "!pip3 install https://download.pytorch.org/whl/cu80/torch-1.0.0-cp36-cp36m-linux_x86_64.whl\n"
      ],
      "execution_count": 68,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Requirement already satisfied: torch==1.0.0 from https://download.pytorch.org/whl/cu80/torch-1.0.0-cp36-cp36m-linux_x86_64.whl in /usr/local/lib/python3.6/dist-packages (1.0.0)\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8neqS39knfqm",
        "colab_type": "text"
      },
      "source": [
        "# util.py"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "0_aJ8OypniO6",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "#import h5py\n",
        "import numpy as np\n",
        "import scipy.io as sio\n",
        "import torch\n",
        "from sklearn import preprocessing\n",
        "import sys\n",
        "from sklearn.cluster import KMeans\n",
        "#val\n",
        "def weights_init(m):\n",
        "    classname = m.__class__.__name__\n",
        "    if classname.find('Linear') != -1:\n",
        "        m.weight.data.normal_(0.0, 0.02)\n",
        "        m.bias.data.fill_(0)\n",
        "    elif classname.find('BatchNorm') != -1:\n",
        "        m.weight.data.normal_(1.0, 0.02)\n",
        "        m.bias.data.fill_(0)\n",
        "\n",
        "def map_label(label, classes):\n",
        "    mapped_label = torch.LongTensor(label.size())\n",
        "    for i in range(classes.size(0)):\n",
        "        mapped_label[label==classes[i]] = i    \n",
        "\n",
        "    return mapped_label\n",
        "\n",
        "class Logger(object):\n",
        "    def __init__(self, filename):\n",
        "        self.filename = filename\n",
        "        f = open(self.filename+'.log', \"a\")\n",
        "        f.close()\n",
        "\n",
        "    def write(self, message):\n",
        "        f = open(self.filename+'.log', \"a\")\n",
        "        f.write(message)  \n",
        "        f.close()\n",
        "\n",
        "class DATA_LOADER(object):\n",
        "    def __init__(self, opt):\n",
        "        if opt.matdataset:\n",
        "            if opt.dataset == 'imageNet1K':\n",
        "                self.read_matimagenet(opt)\n",
        "            else:\n",
        "                self.read_matdataset(opt)\n",
        "        self.index_in_epoch = 0\n",
        "        self.epochs_completed = 0\n",
        "\n",
        "        self.feature_dim = self.train_feature.shape[1]\n",
        "        self.att_dim = self.attribute.shape[1]\n",
        "        self.text_dim = self.att_dim\n",
        "        self.train_cls_num = self.seenclasses.shape[0]\n",
        "        self.test_cls_num = self.unseenclasses.shape[0]\n",
        "        self.tr_cls_centroid = np.zeros([self.seenclasses.shape[0], self.feature_dim], np.float32)\n",
        "        for i in range(self.seenclasses.shape[0]):\n",
        "            self.tr_cls_centroid[i] = np.mean(self.train_feature[torch.nonzero(self.train_mapped_label == i),:].numpy(), axis=0)\n",
        "\n",
        "        n_cluster = opt.n_clusters\n",
        "        real_proto = torch.zeros(n_cluster * self.train_cls_num, self.feature_dim)\n",
        "        for i in range(self.train_cls_num):\n",
        "            sample_idx = (self.train_mapped_label == i).nonzero().squeeze()\n",
        "            if sample_idx.numel() == 0:\n",
        "                real_proto[n_cluster * i: n_cluster * (i+1)] = torch.zeros(n_cluster, self.feature_dim)\n",
        "            else:\n",
        "                real_sample_cls = self.train_feature[sample_idx, :]\n",
        "                y_pred = KMeans(n_clusters=n_cluster, random_state=3).fit_predict(real_sample_cls)\n",
        "                for j in range(n_cluster):\n",
        "                    real_proto[n_cluster*i+j] = torch.from_numpy(real_sample_cls[torch.nonzero(torch.from_numpy(y_pred)==j),:].mean(dim=0).cpu().numpy())\n",
        "        self.real_proto = real_proto\n",
        "\n",
        "                \n",
        "    # not tested\n",
        "    def read_h5dataset(self, opt):\n",
        "        # read image feature\n",
        "        fid = h5py.File(opt.dataroot + \"/\" + opt.dataset + \"/\" + opt.image_embedding + \".hdf5\", 'r')\n",
        "        feature = fid['feature'][()]\n",
        "        label = fid['label'][()] \n",
        "        trainval_loc = fid['trainval_loc'][()] \n",
        "        train_loc = fid['train_loc'][()] \n",
        "        val_unseen_loc = fid['val_unseen_loc'][()] \n",
        "        test_seen_loc = fid['test_seen_loc'][()] \n",
        "        test_unseen_loc = fid['test_unseen_loc'][()] \n",
        "        fid.close()\n",
        "        # read attributes\n",
        "        fid = h5py.File(opt.dataroot + \"/\" + opt.dataset + \"/\" + opt.class_embedding + \".hdf5\", 'r')\n",
        "        self.attribute = fid['attribute'][()]\n",
        "        fid.close()\n",
        "\n",
        "        if not opt.validation:\n",
        "            self.train_feature = feature[trainval_loc] \n",
        "            self.train_label = label[trainval_loc] \n",
        "            self.test_unseen_feature = feature[test_unseen_loc] \n",
        "            self.test_unseen_label = label[test_unseen_loc] \n",
        "            self.test_seen_feature = feature[test_seen_loc] \n",
        "            self.test_seen_label = label[test_seen_loc] \n",
        "        else:\n",
        "            self.train_feature = feature[train_loc] \n",
        "            self.train_label = label[train_loc] \n",
        "            self.test_unseen_feature = feature[val_unseen_loc] \n",
        "            self.test_unseen_label = label[val_unseen_loc] \n",
        "\n",
        "        self.seenclasses = np.unique(self.train_label)\n",
        "        self.unseenclasses = np.unique(self.test_unseen_label)\n",
        "        self.nclasses = self.seenclasses.size(0)\n",
        "\n",
        "    def read_matimagenet(self, opt):\n",
        "        if opt.preprocessing:\n",
        "            print('MinMaxScaler...')\n",
        "            scaler = preprocessing.MinMaxScaler()\n",
        "            matcontent = h5py.File(opt.dataroot + \"/\" + opt.dataset + \"/\" + opt.image_embedding + \".mat\", 'r')\n",
        "            feature = scaler.fit_transform(np.array(matcontent['features']))\n",
        "            label = np.array(matcontent['labels']).astype(int).squeeze() - 1\n",
        "            feature_val = scaler.transform(np.array(matcontent['features_val']))\n",
        "            label_val = np.array(matcontent['labels_val']).astype(int).squeeze() - 1\n",
        "            matcontent.close()\n",
        "            matcontent = h5py.File('/BS/xian/work/data/imageNet21K/extract_res/res101_1crop_2hops_t.mat', 'r')\n",
        "            feature_unseen = scaler.transform(np.array(matcontent['features']))\n",
        "            label_unseen = np.array(matcontent['labels']).astype(int).squeeze() - 1\n",
        "            matcontent.close()\n",
        "        else:\n",
        "            matcontent = h5py.File(opt.dataroot + \"/\" + opt.dataset + \"/\" + opt.image_embedding + \".mat\", 'r')\n",
        "            feature = np.array(matcontent['features'])\n",
        "            label = np.array(matcontent['labels']).astype(int).squeeze() - 1\n",
        "            feature_val = np.array(matcontent['features_val'])\n",
        "            label_val = np.array(matcontent['labels_val']).astype(int).squeeze() - 1\n",
        "            matcontent.close()\n",
        "\n",
        "\n",
        "        matcontent = sio.loadmat(opt.dataroot + \"/\" + opt.dataset + \"/\" + opt.class_embedding + \".mat\")\n",
        "        self.attribute = torch.from_numpy(matcontent['w2v']).float()\n",
        "        self.train_feature = torch.from_numpy(feature).float()\n",
        "        self.train_label = torch.from_numpy(label).long() \n",
        "        self.test_seen_feature = torch.from_numpy(feature_val).float()\n",
        "        self.test_seen_label = torch.from_numpy(label_val).long() \n",
        "        self.test_unseen_feature = torch.from_numpy(feature_unseen).float()\n",
        "        self.test_unseen_label = torch.from_numpy(label_unseen).long() \n",
        "        self.ntrain = self.train_feature.size()[0]\n",
        "        self.seenclasses = torch.from_numpy(np.unique(self.train_label.numpy()))\n",
        "        self.unseenclasses = torch.from_numpy(np.unique(self.test_unseen_label.numpy()))\n",
        "        self.train_class = torch.from_numpy(np.unique(self.train_label.numpy()))\n",
        "        self.ntrain_class = self.seenclasses.size(0)\n",
        "        self.ntest_class = self.unseenclasses.size(0)\n",
        "\n",
        "\n",
        "    def read_matdataset(self, opt):\n",
        "        #path = 'xlsa17/data/'\n",
        "        matcontent = sio.loadmat(opt.dataroot + \"/\" + opt.dataset + \"/\" + opt.image_embedding + \".mat\")\n",
        "        feature = matcontent['features'].T\n",
        "        label = matcontent['labels'].astype(int).squeeze() - 1\n",
        "        matcontent = sio.loadmat(opt.dataroot + \"/\" + opt.dataset + \"/\" + opt.class_embedding + \"_splits.mat\")\n",
        "        # numpy array index starts from 0, matlab starts from 1\n",
        "        trainval_loc = matcontent['trainval_loc'].squeeze() - 1\n",
        "        train_loc = matcontent['train_loc'].squeeze() - 1\n",
        "        val_unseen_loc = matcontent['val_loc'].squeeze() - 1\n",
        "        test_seen_loc = matcontent['test_seen_loc'].squeeze() - 1\n",
        "        test_unseen_loc = matcontent['test_unseen_loc'].squeeze() - 1\n",
        "\n",
        "        self.attribute = torch.from_numpy(matcontent['att'].T).float()\n",
        "        if not opt.validation:\n",
        "            if opt.preprocessing:\n",
        "                if opt.standardization:\n",
        "                    print('standardization...')\n",
        "                    scaler = preprocessing.StandardScaler()\n",
        "                else:\n",
        "                    scaler = preprocessing.MinMaxScaler()\n",
        "\n",
        "                _train_feature = scaler.fit_transform(feature[trainval_loc])\n",
        "                _test_seen_feature = scaler.transform(feature[test_seen_loc])\n",
        "                _test_unseen_feature = scaler.transform(feature[test_unseen_loc])\n",
        "                self.train_feature = torch.from_numpy(_train_feature).float()\n",
        "                mx = self.train_feature.max()\n",
        "                self.train_feature.mul_(1/mx)\n",
        "                self.train_label = torch.from_numpy(label[trainval_loc]).long()\n",
        "                self.test_unseen_feature = torch.from_numpy(_test_unseen_feature).float()\n",
        "                self.test_unseen_feature.mul_(1/mx)\n",
        "                self.test_unseen_label = torch.from_numpy(label[test_unseen_loc]).long()\n",
        "                self.test_seen_feature = torch.from_numpy(_test_seen_feature).float()\n",
        "                self.test_seen_feature.mul_(1/mx)\n",
        "                self.test_seen_label = torch.from_numpy(label[test_seen_loc]).long()\n",
        "            else:\n",
        "                self.train_feature = torch.from_numpy(feature[trainval_loc]).float()\n",
        "                self.train_label = torch.from_numpy(label[trainval_loc]).long()\n",
        "                self.test_unseen_feature = torch.from_numpy(feature[test_unseen_loc]).float()\n",
        "                self.test_unseen_label = torch.from_numpy(label[test_unseen_loc]).long()\n",
        "                self.test_seen_feature = torch.from_numpy(feature[test_seen_loc]).float()\n",
        "                self.test_seen_label = torch.from_numpy(label[test_seen_loc]).long()\n",
        "        else:\n",
        "            self.train_feature = torch.from_numpy(feature[train_loc]).float()\n",
        "            self.train_label = torch.from_numpy(label[train_loc]).long()\n",
        "            self.test_unseen_feature = torch.from_numpy(feature[val_unseen_loc]).float()\n",
        "            self.test_unseen_label = torch.from_numpy(label[val_unseen_loc]).long()\n",
        "\n",
        "        self.seenclasses = torch.from_numpy(np.unique(self.train_label.numpy()))\n",
        "        self.unseenclasses = torch.from_numpy(np.unique(self.test_unseen_label.numpy()))\n",
        "        self.ntrain = self.train_feature.size()[0]\n",
        "        self.ntrain_class = self.seenclasses.size(0)\n",
        "        self.ntest_class = self.unseenclasses.size(0)\n",
        "        self.train_class = self.seenclasses.clone()\n",
        "        self.allclasses = torch.arange(0, self.ntrain_class+self.ntest_class).long()\n",
        "        self.train_mapped_label = map_label(self.train_label, self.seenclasses)\n",
        "        self.train_att = self.attribute[self.seenclasses].numpy()\n",
        "        self.test_att  = self.attribute[self.unseenclasses].numpy()\n",
        "        self.train_cls_num = self.ntrain_class\n",
        "        self.test_cls_num  = self.ntest_class\n",
        "\n",
        "    def next_batch_one_class(self, batch_size):\n",
        "        if self.index_in_epoch == self.ntrain_class:\n",
        "            self.index_in_epoch = 0 \n",
        "            perm = torch.randperm(self.ntrain_class)\n",
        "            self.train_class[perm] = self.train_class[perm]\n",
        "\n",
        "        iclass = self.train_class[self.index_in_epoch]\n",
        "        idx = self.train_label.eq(iclass).nonzero().squeeze()\n",
        "        perm = torch.randperm(idx.size(0))\n",
        "        idx = idx[perm]\n",
        "        iclass_feature = self.train_feature[idx]\n",
        "        iclass_label = self.train_label[idx]\n",
        "        self.index_in_epoch += 1\n",
        "        return iclass_feature[0:batch_size], iclass_label[0:batch_size], self.attribute[iclass_label[0:batch_size]] \n",
        "    \n",
        "    def next_batch(self, batch_size):\n",
        "        idx = torch.randperm(self.ntrain)[0:batch_size]\n",
        "        batch_feature = self.train_feature[idx]\n",
        "        batch_label = self.train_label[idx]\n",
        "        batch_att = self.attribute[batch_label]\n",
        "        return batch_feature, batch_label, batch_att\n",
        "    #classifier\n",
        "    # select batch samples by randomly drawing batch_size classes    \n",
        "    def next_batch_uniform_class(self, batch_size):\n",
        "        batch_class = torch.LongTensor(batch_size)\n",
        "        for i in range(batch_size):\n",
        "            idx = torch.randperm(self.ntrain_class)[0]\n",
        "            batch_class[i] = self.train_class[idx]\n",
        "            \n",
        "        batch_feature = torch.FloatTensor(batch_size, self.train_feature.size(1))       \n",
        "        batch_label = torch.LongTensor(batch_size)\n",
        "        batch_att = torch.FloatTensor(batch_size, self.attribute.size(1))\n",
        "        for i in range(batch_size):\n",
        "            iclass = batch_class[i]\n",
        "            idx_iclass = self.train_label.eq(iclass).nonzero().squeeze()\n",
        "            idx_in_iclass = torch.randperm(idx_iclass.size(0))[0]\n",
        "            idx_file = idx_iclass[idx_in_iclass]\n",
        "            batch_feature[i] = self.train_feature[idx_file]\n",
        "            batch_label[i] = self.train_label[idx_file]\n",
        "            batch_att[i] = self.attribute[batch_label[i]] \n",
        "        return batch_feature, batch_label, batch_att"
      ],
      "execution_count": 69,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sNYiyzww9aQF",
        "colab_type": "text"
      },
      "source": [
        "# classifier.py"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "_0B_kRB61Ptz",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "import torch\n",
        "import torch.nn as nn\n",
        "from torch.autograd import Variable\n",
        "import torch.optim as optim\n",
        "import numpy as np\n",
        "from sklearn.preprocessing import MinMaxScaler \n",
        "import sys\n",
        "\n",
        "class CLASSIFIER:\n",
        "    # train_Y is interger \n",
        "    def __init__(self, _train_X, _train_Y,  _nclass, _input_dim, _cuda, _lr=0.001, _beta1=0.5, _nepoch=20, _batch_size=100, pretrain_classifer=''):\n",
        "        self.train_X =  _train_X \n",
        "        self.train_Y = _train_Y \n",
        "        self.batch_size = _batch_size\n",
        "        self.nepoch = _nepoch\n",
        "        self.nclass = _nclass\n",
        "        self.dim = _input_dim\n",
        "        self.cuda = _cuda\n",
        "        self.model =  LINEAR_LOGSOFTMAX(self.dim, self.nclass)\n",
        "        self.model.apply(weights_init)\n",
        "        self.criterion = nn.NLLLoss()\n",
        "        \n",
        "        self.input = torch.FloatTensor(_batch_size, self.dim) \n",
        "        self.label = torch.LongTensor(_batch_size) \n",
        "        \n",
        "        self.lr = _lr\n",
        "        self.beta1 = _beta1\n",
        "        # setup optimizer\n",
        "        self.optimizer = optim.Adam(self.model.parameters(), lr=_lr, betas=(_beta1, 0.999))\n",
        "\n",
        "        if self.cuda:\n",
        "            self.model.cuda()\n",
        "            self.criterion.cuda()\n",
        "            self.input = self.input.cuda()\n",
        "            self.label = self.label.cuda()\n",
        "\n",
        "        self.index_in_epoch = 0\n",
        "        self.epochs_completed = 0\n",
        "        self.ntrain = self.train_X.size()[0]\n",
        "        #fake\n",
        "        if pretrain_classifer == '':\n",
        "            self.fit()\n",
        "        else:\n",
        "            self.model.load_state_dict(torch.load(pretrain_classifier))\n",
        "    \n",
        "\n",
        "    def fit(self):\n",
        "        for epoch in range(self.nepoch):\n",
        "            for i in range(0, self.ntrain, self.batch_size):      \n",
        "                self.model.zero_grad()\n",
        "                batch_input, batch_label = self.next_batch(self.batch_size) \n",
        "                self.input.copy_(batch_input)\n",
        "                self.label.copy_(batch_label)\n",
        "                   \n",
        "                inputv = Variable(self.input)\n",
        "                labelv = Variable(self.label)\n",
        "                output = self.model(inputv)\n",
        "                loss = self.criterion(output, labelv)\n",
        "                loss.backward()\n",
        "                self.optimizer.step()\n",
        "                     \n",
        "    def next_batch(self, batch_size):\n",
        "        start = self.index_in_epoch\n",
        "        # shuffle the data at the first epoch\n",
        "        if self.epochs_completed == 0 and start == 0:\n",
        "            perm = torch.randperm(self.ntrain)\n",
        "            self.train_X = self.train_X[perm]\n",
        "            self.train_Y = self.train_Y[perm]\n",
        "        # the last batch\n",
        "        if start + batch_size > self.ntrain:\n",
        "            self.epochs_completed += 1\n",
        "            rest_num_examples = self.ntrain - start\n",
        "            if rest_num_examples > 0:\n",
        "                X_rest_part = self.train_X[start:self.ntrain]\n",
        "                Y_rest_part = self.train_Y[start:self.ntrain]\n",
        "            # shuffle the data\n",
        "            perm = torch.randperm(self.ntrain)\n",
        "            self.train_X = self.train_X[perm]\n",
        "            self.train_Y = self.train_Y[perm]\n",
        "            # start next epoch\n",
        "            start = 0\n",
        "            self.index_in_epoch = batch_size - rest_num_examples\n",
        "            end = self.index_in_epoch\n",
        "            X_new_part = self.train_X[start:end]\n",
        "            Y_new_part = self.train_Y[start:end]\n",
        "            if rest_num_examples > 0:\n",
        "                return torch.cat((X_rest_part, X_new_part), 0) , torch.cat((Y_rest_part, Y_new_part), 0)\n",
        "            else:\n",
        "                return X_new_part, Y_new_part\n",
        "        else:\n",
        "            self.index_in_epoch += batch_size\n",
        "            end = self.index_in_epoch\n",
        "            # from index start to index end-1\n",
        "            return self.train_X[start:end], self.train_Y[start:end]\n",
        "\n",
        "    def compute_per_class_acc(self, test_label, predicted_label, nclass):\n",
        "        acc_per_class = torch.FloatTensor(nclass).fill_(0)\n",
        "        for i in range(nclass):\n",
        "            idx = (test_label == i)\n",
        "            acc_per_class[i] = torch.sum(test_label[idx]==predicted_label[idx]).float()/ torch.sum(idx)\n",
        "        return acc_per_class.mean() \n",
        "\n",
        "    # test_label is integer \n",
        "    def val(self, test_X, test_label, target_classes): \n",
        "        start = 0\n",
        "        ntest = test_X.size()[0]\n",
        "        predicted_label = torch.LongTensor(test_label.size())\n",
        "        for i in range(0, ntest, self.batch_size):\n",
        "            end = min(ntest, start+self.batch_size)\n",
        "            if self.cuda:\n",
        "                output = self.model(Variable(test_X[start:end].cuda(), volatile=True)) \n",
        "            else:\n",
        "                output = self.model(Variable(test_X[start:end], volatile=True)) \n",
        "            _, predicted_label[start:end] = torch.max(output.data, 1)\n",
        "            start = end\n",
        "\n",
        "        acc = self.compute_per_class_acc(map_label(test_label, target_classes), predicted_label, target_classes.size(0))\n",
        "        return acc\n",
        "\n",
        "\n",
        "  "
      ],
      "execution_count": 70,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "x49_ZY4y7UN-",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "class LINEAR_LOGSOFTMAX(nn.Module):\n",
        "    def __init__(self, input_dim, nclass):\n",
        "        super(LINEAR_LOGSOFTMAX, self).__init__()\n",
        "        self.fc = nn.Linear(input_dim, nclass)\n",
        "        self.logic = nn.LogSoftmax(dim=1)\n",
        "    def forward(self, x): \n",
        "        o = self.logic(self.fc(x))\n",
        "        return o"
      ],
      "execution_count": 71,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "ZdFiQG4oGLuf",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        ""
      ],
      "execution_count": 71,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "I-aEWd7dm9XK",
        "colab_type": "text"
      },
      "source": [
        "# classifier2.py"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "s-VxQiCDmp4A",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "import torch\n",
        "import torch.nn as nn\n",
        "from torch.autograd import Variable\n",
        "import torch.optim as optim\n",
        "import numpy as np\n",
        "from termcolor import cprint\n",
        "\n",
        "\n",
        "import itertools\n",
        "import os\n",
        "import sys\n",
        "\n",
        "import matplotlib.pyplot as plt\n",
        "import numpy as np\n",
        "import torch.nn.functional as F\n",
        "from scipy.stats import entropy\n",
        "from sklearn.metrics import confusion_matrix\n",
        "\n",
        "import time\n",
        "\n",
        "#CLASSIFIER\n",
        "class CLASSIFIER2:\n",
        "    # train_Y is interger\n",
        "    # CLASSIFIER(syn_feature,util.map_label(syn_label,data.unseenclasses),data,data.unseenclasses.size(0),opt.cuda,opt.classifier_lr, 0.5, 25, opt.syn_num, False)\n",
        "    def __init__(self, _train_X, _train_Y, data_loader, _nclass, _cuda, _lr=0.001, _beta1=0.5, _nepoch=20, _batch_size=100, generalized=True,ratio=0.6,epoch=20):\n",
        "        self.train_X =  _train_X \n",
        "        self.train_Y = _train_Y \n",
        "        self.test_seen_feature = data_loader.test_seen_feature\n",
        "        self.test_seen_label = data_loader.test_seen_label \n",
        "        self.test_unseen_feature = data_loader.test_unseen_feature\n",
        "        self.test_unseen_label = data_loader.test_unseen_label \n",
        "        self.seenclasses = data_loader.seenclasses\n",
        "        self.unseenclasses = data_loader.unseenclasses\n",
        "        self.batch_size = _batch_size\n",
        "        self.nepoch = _nepoch\n",
        "        self.nclass = _nclass\n",
        "        self.input_dim = _train_X.size(1)\n",
        "        self.cuda = _cuda\n",
        "        self.model =  LINEAR_LOGSOFTMAX(self.input_dim, self.nclass)\n",
        "        self.model.apply(weights_init)\n",
        "        self.criterion = nn.NLLLoss()\n",
        "\n",
        "        self.data = data_loader\n",
        "\n",
        "        self.input = torch.FloatTensor(_batch_size, self.input_dim) \n",
        "        self.label = torch.LongTensor(_batch_size) \n",
        "        \n",
        "        self.lr = _lr\n",
        "        self.beta1 = _beta1\n",
        "        # setup optimizer\n",
        "        self.optimizer = optim.Adam(self.model.parameters(), lr=_lr, betas=(_beta1, 0.999))\n",
        "        self.ratio = ratio\n",
        "        self.epoch = epoch\n",
        "\n",
        "        if self.cuda:\n",
        "            self.model.cuda()\n",
        "            self.criterion.cuda()\n",
        "            self.input = self.input.cuda()\n",
        "            self.label = self.label.cuda()\n",
        "\n",
        "        self.index_in_epoch = 0\n",
        "        self.epochs_completed = 0\n",
        "        self.ntrain = self.train_X.size()[0]\n",
        "        self.backup_X = _train_X\n",
        "        self.backup_Y = _train_Y\n",
        "\n",
        "        if generalized:\n",
        "            self.acc_seen, self.acc_unseen, self.H = self.fit()\n",
        "        else:\n",
        "            self.acc = self.fit_zsl()\n",
        "\n",
        "    def pairwise_distances(self,x, y=None):\n",
        "        '''\n",
        "        float\n",
        "        Input: x is a Nxd matrix\n",
        "               y is an optional Mxd matirx\n",
        "        Output: dist is a NxM matrix where dist[i,j] is the square norm between x[i,:] and y[j,:]\n",
        "                if y is not given then use 'y=x'.\n",
        "        i.e. dist[i,j] = ||x[i,:]-y[j,:]||^2\n",
        "        '''\n",
        "        x_norm = (x ** 2).sum(1).view(-1, 1)\n",
        "        if y is not None:\n",
        "            y_t = torch.transpose(y, 0, 1)\n",
        "            y_norm = (y ** 2).sum(1).view(1, -1)\n",
        "        else:\n",
        "            y_t = torch.transpose(x, 0, 1)\n",
        "            y_norm = x_norm.view(1, -1)\n",
        "\n",
        "        dist = x_norm + y_norm - 2.0 * torch.mm(x, y_t)\n",
        "        # Ensure diagonal is zero if x=y\n",
        "        if y is None:\n",
        "            dist = dist - torch.diag(dist.diag)\n",
        "        return torch.clamp(dist, 0.0, np.inf)\n",
        "\n",
        "    def fit_zsl(self):\n",
        "        first_acc=0\n",
        "        first_all_pred = None\n",
        "        first_all_output = None\n",
        "        first_all_acc = []\n",
        "\n",
        "        trun = lambda x: int(x * 100)\n",
        "\n",
        "        all_length = self.test_unseen_feature.size(0)\n",
        "        mapped_test_label = map_label(self.test_unseen_label, self.unseenclasses)\n",
        "        for epoch in range(self.nepoch):\n",
        "            for i in range(0, self.ntrain, self.batch_size):\n",
        "                self.model.zero_grad()\n",
        "                batch_input, batch_label = self.next_batch(self.batch_size)\n",
        "                self.input.copy_(batch_input)\n",
        "                self.label.copy_(batch_label)\n",
        "                inputv = Variable(self.input)  # fake_feature\n",
        "                labelv = Variable(self.label)  # fake_labels\n",
        "                output = self.model(inputv)\n",
        "                loss = self.criterion(output, labelv)  # fake_unseen_feature labels\n",
        "                loss.backward()\n",
        "                self.optimizer.step()\n",
        "\n",
        "            acc, pred, output,all_acc = self.val(self.test_unseen_feature, self.test_unseen_label, self.unseenclasses)\n",
        "            if acc > first_acc:\n",
        "                first_acc = acc\n",
        "                first_all_pred = pred\n",
        "                first_all_output = output\n",
        "                first_all_acc = all_acc\n",
        "        print('First Acc: {:.2f}%'.format(first_acc * 100))\n",
        "        # print([trun(x) for  x in  list(first_all_acc)])\n",
        "        # cprint('First Acc: {:.2f}%'.format(first_acc * 100),'red')\n",
        "        easy_len = int(all_length*self.ratio)\n",
        "        hard_len = all_length - easy_len\n",
        "        entropy_value = torch.from_numpy(np.asarray(list(map(entropy,first_all_output.data.cpu()))))\n",
        "        _, indices = torch.sort(-entropy_value)\n",
        "        exit_indices = indices[:easy_len]\n",
        "        keep_indices = indices[easy_len:]\n",
        "\n",
        "        first_easy_pred = first_all_pred[exit_indices]\n",
        "        first_easy_label = mapped_test_label[exit_indices]\n",
        "        first_hard_pred = first_all_pred[keep_indices]\n",
        "        first_hard_label = mapped_test_label[keep_indices]\n",
        "        acc_first_easy = self.compute_per_class_acc(first_easy_label,first_easy_pred,self.unseenclasses.size(0))\n",
        "        acc_first_hard = self.compute_per_class_acc(first_hard_label,first_hard_pred,self.unseenclasses.size(0))\n",
        "        all_easy_hard_label = torch.cat( (first_easy_label,first_hard_label),0 )\n",
        "        # print('First Easy Acc:{:.2f}%'.format(acc_first_easy*100))\n",
        "        # print('First Hard Acc:{:.2f}%'.format(acc_first_hard*100))\n",
        "\n",
        "        self.index_in_epoch = 0\n",
        "        self.epochs_completed = 0\n",
        "        self.ntrain = self.backup_X.size()[0] + easy_len # fake+easy_sample\n",
        "        self.train_X = torch.cat( (self.backup_X, self.test_unseen_feature[exit_indices] ),0 )\n",
        "        self.train_Y = torch.cat( (self.backup_Y, first_easy_pred ),0 )\n",
        "\n",
        "        sims = self.pairwise_distances(self.test_unseen_feature[keep_indices], self.train_X)\n",
        "        value,idx = torch.min(sims,dim=1)\n",
        "        knn_hard_pred = self.train_Y[idx]\n",
        "        knn_all_pred = torch.cat( (first_easy_pred,knn_hard_pred),0 )\n",
        "\n",
        "        acc_knn_hard = self.compute_per_class_acc(first_hard_label, knn_hard_pred,self.unseenclasses.size(0))\n",
        "        acc_knn = self.compute_per_class_acc(all_easy_hard_label,knn_all_pred,self.unseenclasses.size(0))\n",
        "        all_acc_knn = self.compute_every_class_acc(all_easy_hard_label,knn_all_pred,self.unseenclasses.size(0))\n",
        "        \n",
        "        #print('1NN Hard Acc: {:.2f}%'.format(acc_knn_hard*100))\n",
        "        print('1NN   Acc: {:.2f}%'.format(acc_knn*100))\n",
        "        #print([trun(x) for x in list(all_acc_knn)])\n",
        "\n",
        "        acc_fc_hard = 0\n",
        "        fc_hard_pred = None\n",
        "        real_mean_acc = 0\n",
        "        for epoch in range(self.nepoch):\n",
        "            for i in range(0, self.ntrain, self.batch_size):\n",
        "                self.model.zero_grad()\n",
        "                batch_input, batch_label = self.next_batch(self.batch_size)\n",
        "                self.input.copy_(batch_input)\n",
        "                self.label.copy_(batch_label)\n",
        "\n",
        "                inputv = Variable(self.input)  # fake_feature\n",
        "                labelv = Variable(self.label)  # fake_labels\n",
        "                output = self.model(inputv)\n",
        "                loss = self.criterion(output, labelv)  # 使用fake_unseen_feature和labels来训练分类器\n",
        "                loss.backward()\n",
        "                self.optimizer.step()\n",
        "            acc, pred, output,_ = self.val(self.test_unseen_feature[keep_indices],self.test_unseen_label[keep_indices],self.unseenclasses)\n",
        "            correct_num = pred.eq(mapped_test_label[keep_indices]).cpu().sum().float()\n",
        "            all_length = output.size(0)\n",
        "            first_acc = correct_num / all_length\n",
        "            if first_acc > acc_fc_hard:\n",
        "                acc_fc_hard = acc\n",
        "                fc_hard_pred = pred\n",
        "                real_mean_acc = first_acc\n",
        "        fc_all_pred = torch.cat( (first_easy_pred,fc_hard_pred),0 )\n",
        "        acc_fc_hard = self.compute_per_class_acc(first_hard_label, fc_hard_pred,self.unseenclasses.size(0))\n",
        "        acc_fc = self.compute_per_class_acc(all_easy_hard_label,fc_all_pred,self.unseenclasses.size(0))\n",
        "        all_acc_fc = self.compute_every_class_acc(all_easy_hard_label,fc_all_pred,self.unseenclasses.size(0))\n",
        "        \n",
        "        #print('FC Hard Acc: {:.2f}%'.format(acc_fc_hard*100))\n",
        "        print('FC    Acc: {:.2f}%'.format(acc_fc*100))\n",
        "        #print([trun(x) for x in list(all_acc_fc)])\n",
        "        #cprint('FC Overall Acc: {:.2f}%\\n'.format(acc_fc*100),'red')\n",
        "\n",
        "        sys.stdout.flush()\n",
        "        return acc_fc \n",
        "\n",
        "\n",
        "\n",
        "    def split_pred(self,all_pred, real_label):\n",
        "        seen_pred = None\n",
        "        seen_label = None\n",
        "        unseen_pred = None\n",
        "        unseen_label = None\n",
        "        for i in self.seenclasses:\n",
        "            idx = (real_label == i)\n",
        "            if seen_pred is None:\n",
        "                seen_pred = all_pred[idx]\n",
        "                seen_label = real_label[idx]\n",
        "            else:\n",
        "                seen_pred = torch.cat( (seen_pred,all_pred[idx]),0 )\n",
        "                seen_label = torch.cat( (seen_label, real_label[idx]) )\n",
        "\n",
        "        for i in self.unseenclasses:\n",
        "            idx = (real_label == i)\n",
        "            if unseen_pred is None:\n",
        "                unseen_pred = all_pred[idx]\n",
        "                unseen_label = real_label[idx]\n",
        "            else:\n",
        "                unseen_pred = torch.cat( (unseen_pred,all_pred[idx]),0 )\n",
        "                unseen_label = torch.cat(  (unseen_label, real_label[idx]), 0 )\n",
        "\n",
        "        return seen_pred, seen_label, unseen_pred, unseen_label\n",
        "\n",
        "\n",
        "\n",
        "    # for gzsl\n",
        "    def fit(self):\n",
        "        test_seen_length = self.test_seen_feature.shape[0] #1764\n",
        "        test_unseen_length = self.test_unseen_feature.shape[0] #2967\n",
        "        all_length = test_seen_length + test_unseen_length\n",
        "        all_test_feature = torch.cat( (self.test_seen_feature,self.test_unseen_feature), 0 )\n",
        "        all_test_label = torch.cat( (self.test_seen_label, self.test_unseen_label), 0 )\n",
        "        all_classes = torch.sort(torch.cat( (self.seenclasses,self.unseenclasses),0 ))[0]\n",
        "        first_acc = 0\n",
        "        first_all_pred = None\n",
        "        first_all_output = None\n",
        "\n",
        "        best_H = 0\n",
        "        for epoch in range(self.nepoch):\n",
        "            for i in range(0, self.ntrain, self.batch_size): #self.ntrain=22057, self.batch_size=300\n",
        "                self.model.zero_grad()\n",
        "                #print(\"1111\")\n",
        "                #torch.no_grad()\n",
        "                batch_input, batch_label = self.next_batch(self.batch_size)\n",
        "                #print(\"2222\")\n",
        "                self.input.copy_(batch_input)\n",
        "                self.label.copy_(batch_label)\n",
        "                #print(\"3333\")\n",
        "                inputv = Variable(self.input)\n",
        "                labelv = Variable(self.label)\n",
        "                output = self.model(inputv)\n",
        "                loss = self.criterion(output, labelv)\n",
        "                loss.backward()\n",
        "                #print(\"4444\")\n",
        "                self.optimizer.step()\n",
        "            acc_seen,pred_seen,output_seen = self.val_gzsl(self.test_seen_feature, self.test_seen_label, self.seenclasses)\n",
        "            acc_unseen,pred_unseen,output_unseen = self.val_gzsl(self.test_unseen_feature, self.test_unseen_label, self.unseenclasses)\n",
        "            H = (2 * acc_seen * acc_unseen / (acc_seen + acc_unseen).float()) + 1e-10\n",
        "            if H > best_H:\n",
        "                best_H = H\n",
        "                first_all_pred = torch.cat( (pred_seen,pred_unseen), 0 )\n",
        "                first_all_output = torch.cat( (output_seen, output_unseen), 0 )\n",
        "        first_seen_pred,first_seen_label,first_unseen_pred,first_unseen_label = self.split_pred(first_all_pred,all_test_label)\n",
        "        #def compute_per_class_acc_gzsl(self, test_label, predicted_label, target_classes):\n",
        "        acc_first_seen = self.compute_per_class_acc_gzsl(first_seen_label, first_seen_pred,self.seenclasses)\n",
        "        acc_first_unseen = self.compute_per_class_acc_gzsl(first_unseen_label, first_unseen_pred,self.unseenclasses)\n",
        "        acc_first_H = 2*acc_first_seen*acc_first_unseen/(acc_first_seen+acc_first_unseen)\n",
        "        print('First Seen: {:.2f}%, Unseen: {:.2f}%, First H: {:.2f}%'.format(acc_first_seen*100,acc_first_unseen*100,acc_first_H*100))\n",
        "        # print('First Unseen Acc: {:.2f}%'.format(acc_first_unseen*100))\n",
        "        # print('First Harmonic Acc: {:.2f}%\\n'.format(acc_first_H*100))\n",
        "\n",
        "        easy_length = int(all_length*self.ratio)\n",
        "        hard_length = all_length - easy_length\n",
        "        first_all_output = first_all_output.cpu()\n",
        "        entropy_value = torch.from_numpy(np.asarray(list(map(entropy, first_all_output.data))))\n",
        "        _, indices = torch.sort(-entropy_value)\n",
        "        exit_indices = indices[:easy_length]\n",
        "        keep_indices = indices[easy_length:]\n",
        "        first_easy_pred = first_all_pred[exit_indices]\n",
        "        first_easy_label = all_test_label[exit_indices]\n",
        "        first_hard_pred = first_all_pred[keep_indices]\n",
        "        first_hard_label = all_test_label[keep_indices]\n",
        "        all_easy_hard_label = torch.cat( (first_easy_label,first_hard_label),0 )\n",
        "\n",
        "        acc_first_easy = self.compute_per_class_acc_gzsl(first_easy_label,first_easy_pred,all_classes)\n",
        "        acc_first_hard = self.compute_per_class_acc_gzsl(first_hard_label,first_hard_pred,all_classes)\n",
        "        # print('First Easy Acc: {:.2f}%'.format(acc_first_easy*100))\n",
        "        # print('First Hard Acc: {:.2f}%'.format(acc_first_hard*100))\n",
        "\n",
        "        self.index_in_epoch = 0\n",
        "        self.epochs_completed = 0\n",
        "        self.ntrain = self.backup_X.size(0) + easy_length\n",
        "        self.train_X = torch.cat( (self.backup_X, all_test_feature[exit_indices]),0 )\n",
        "        self.train_Y = torch.cat( (self.backup_Y, first_easy_pred),0)\n",
        "\n",
        "        sims = self.pairwise_distances(all_test_feature[keep_indices], self.train_X)\n",
        "        value, idx = torch.min(sims, dim=1)\n",
        "        knn_hard_pred = self.train_Y[idx]\n",
        "        knn_all_pred = torch.cat( (first_easy_pred,knn_hard_pred),0 )\n",
        "        knn_seen_pred,knn_seen_label,knn_unseen_pred,knn_unseen_label = self.split_pred(knn_all_pred,all_easy_hard_label)\n",
        "        acc_knn_seen = self.compute_per_class_acc_gzsl(knn_seen_label,knn_seen_pred,self.seenclasses)\n",
        "        acc_knn_unseen = self.compute_per_class_acc_gzsl(knn_unseen_label,knn_unseen_pred,self.unseenclasses)\n",
        "        acc_knn_H = 2*acc_knn_seen*acc_knn_unseen/(acc_knn_seen+acc_knn_unseen)\n",
        "        print('1NN   Seen: {:.2f}%, Unseen: {:.2f}%, 1NN H: {:.2f}%'.format(acc_knn_seen*100,acc_knn_unseen*100,acc_knn_H*100))\n",
        "        acc_knn_hard = self.compute_per_class_acc_gzsl(first_hard_label,knn_hard_pred,all_classes)\n",
        "\n",
        "        '''\n",
        "        print(\"aaaaaaaaaaaaaaaaaa\")\n",
        "        print('1NN Unseen Acc: {:.2f}%'.format(acc_knn_unseen*100))\n",
        "        print('1NN H Acc: {:.2f}%'.format(acc_knn_H*100))\n",
        "        print('1NN Hard Acc: {:.2f}%'.format(acc_knn_hard*100))\n",
        "        print(\"bbbbbbbbbbbbbbbbb\")\n",
        "        '''\n",
        "        best_fc_hard_acc = 0\n",
        "        fc_hard_pred = None\n",
        "        for epoch in range(self.nepoch):\n",
        "            for i in range(0, self.ntrain, self.batch_size):\n",
        "                self.model.zero_grad()\n",
        "                batch_input, batch_label = self.next_batch(self.batch_size)\n",
        "                self.input.copy_(batch_input)\n",
        "                self.label.copy_(batch_label)\n",
        "                inputv = Variable(self.input)  # fake_feature\n",
        "                labelv = Variable(self.label)  # fake_labels\n",
        "                output = self.model(inputv)\n",
        "                loss = self.criterion(output, labelv)  # 使用fake_unseen_feature和labels来训练分类器\n",
        "                loss.backward()\n",
        "                self.optimizer.step()\n",
        "\n",
        "            acc,pred,_ = self.val_gzsl(all_test_feature[keep_indices],first_hard_label,all_classes)\n",
        "            if acc > best_fc_hard_acc:\n",
        "                fc_hard_pred = pred\n",
        "\n",
        "        fc_all_pred = torch.cat((first_easy_pred, fc_hard_pred), 0)\n",
        "        fc_seen_pred, fc_seen_label, fc_unseen_pred, fc_unseen_label = self.split_pred(fc_all_pred,all_easy_hard_label)\n",
        "        acc_fc_seen = self.compute_per_class_acc_gzsl(fc_seen_label, fc_seen_pred, self.seenclasses)\n",
        "        acc_fc_unseen = self.compute_per_class_acc_gzsl(fc_unseen_label, fc_unseen_pred, self.unseenclasses)\n",
        "        acc_fc_H = 2 * acc_fc_seen * acc_fc_unseen / (acc_fc_seen + acc_fc_unseen)\n",
        "        print('FC    Seen: {:.2f}%, Unseen: {:.2f}%, FC H: {:.2f}%'.format(acc_fc_seen * 100,acc_fc_unseen * 100,acc_fc_H * 100))\n",
        "        acc_fc_hard = self.compute_per_class_acc_gzsl(first_hard_label,fc_hard_pred,all_classes)\n",
        "        '''\n",
        "        print(\"AAAAAAAAAAAAAA\")\n",
        "        print('FC Unseen Acc: {:.2f}%'.format(acc_fc_unseen * 100))\n",
        "        print('FC H Acc: {:.2f}%'.format(acc_fc_H * 100))\n",
        "\n",
        "        print('FC Hard Acc: {:.2f}%\\n'.format(acc_fc_hard*100))\n",
        "        print(\"BBBBBBBBBBBBBBBBBBBBB\")\n",
        "        '''\n",
        "        sys.stdout.flush()\n",
        "        return acc_fc_seen,acc_fc_unseen,acc_fc_H\n",
        "\n",
        "    def val(self, test_X, test_label, target_classes,second=False):\n",
        "        start = 0\n",
        "        ntest = test_X.size()[0]\n",
        "        predicted_label = torch.LongTensor(test_label.size())\n",
        "        all_output = None\n",
        "        for i in range(0, ntest, self.batch_size):\n",
        "            end = min(ntest, start+self.batch_size)\n",
        "            if self.cuda:\n",
        "                output = self.model(Variable(test_X[start:end].cuda(), volatile=True))\n",
        "            else:\n",
        "                output = self.model(Variable(test_X[start:end], volatile=True))\n",
        "            if all_output is None:\n",
        "                all_output = output\n",
        "            else:\n",
        "                all_output = torch.cat( (all_output, output), 0 )\n",
        "            _, predicted_label[start:end] = torch.max(output.data, 1)\n",
        "            start = end\n",
        "        acc = self.compute_per_class_acc(map_label(test_label, target_classes), predicted_label, target_classes.size(0))\n",
        "        acc_all = self.compute_every_class_acc(map_label(test_label, target_classes), predicted_label, target_classes.size(0))\n",
        "        return acc, predicted_label, all_output,acc_all\n",
        "\n",
        "    def val_gzsl(self, test_X, test_label, target_classes):\n",
        "        start = 0\n",
        "        ntest = test_X.size()[0]\n",
        "        predicted_label = torch.LongTensor(test_label.size())\n",
        "        all_output = None\n",
        "        for i in range(0, ntest, self.batch_size):\n",
        "            end = min(ntest, start+self.batch_size)\n",
        "            if self.cuda:\n",
        "                output = self.model(Variable(test_X[start:end].cuda(), volatile=True))\n",
        "            else:\n",
        "                output = self.model(Variable(test_X[start:end], volatile=True))\n",
        "\n",
        "            if all_output is None:\n",
        "                all_output = output\n",
        "            else:\n",
        "                all_output = torch.cat( (all_output, output), 0 )\n",
        "            _, predicted_label[start:end] = torch.max(output.data, 1)\n",
        "            start = end\n",
        "        # acc = self.compute_per_class_acc(util.map_label(test_label, target_classes), predicted_label, target_classes.size(0))\n",
        "        acc = self.compute_per_class_acc_gzsl(test_label, predicted_label, target_classes)\n",
        "        return acc, predicted_label, all_output \n",
        "\n",
        "    def next_batch(self, batch_size):\n",
        "        start = self.index_in_epoch\n",
        "        # shuffle the data at the first epoch\n",
        "        if self.epochs_completed == 0 and start == 0:\n",
        "            perm = torch.randperm(self.ntrain)\n",
        "            self.train_X = self.train_X[perm]\n",
        "            self.train_Y = self.train_Y[perm]\n",
        "        # the last batch\n",
        "        if start + batch_size > self.ntrain:\n",
        "            self.epochs_completed += 1\n",
        "            rest_num_examples = self.ntrain - start\n",
        "            if rest_num_examples > 0:\n",
        "                X_rest_part = self.train_X[start:self.ntrain]\n",
        "                Y_rest_part = self.train_Y[start:self.ntrain]\n",
        "            # shuffle the data\n",
        "            perm = torch.randperm(self.ntrain)\n",
        "            self.train_X = self.train_X[perm]\n",
        "            self.train_Y = self.train_Y[perm]\n",
        "            # start next epoch\n",
        "            start = 0\n",
        "            self.index_in_epoch = batch_size - rest_num_examples\n",
        "            end = self.index_in_epoch\n",
        "            X_new_part = self.train_X[start:end]\n",
        "            Y_new_part = self.train_Y[start:end]\n",
        "            if rest_num_examples > 0:\n",
        "                return torch.cat((X_rest_part, X_new_part), 0) , torch.cat((Y_rest_part, Y_new_part), 0)\n",
        "            else:\n",
        "                return X_new_part, Y_new_part\n",
        "        else:\n",
        "            self.index_in_epoch += batch_size\n",
        "            end = self.index_in_epoch\n",
        "            return self.train_X[start:end], self.train_Y[start:end]\n",
        "\n",
        "    def compute_per_class_acc_gzsl(self, test_label, predicted_label, target_classes):\n",
        "        acc_per_class = 0\n",
        "        for i in target_classes:\n",
        "            idx = (test_label == i)\n",
        "            if torch.sum(idx) == 0:\n",
        "                continue\n",
        "            else:\n",
        "                acc_per_class += torch.sum(test_label[idx]==predicted_label[idx]).float() / torch.sum(idx)\n",
        "        acc_per_class /= target_classes.size(0)\n",
        "        return acc_per_class \n",
        "\n",
        "    def compute_per_class_acc(self, test_label, predicted_label, nclass):\n",
        "        acc_per_class = torch.FloatTensor(nclass).fill_(0)\n",
        "        for i in range(nclass):\n",
        "            idx = (test_label == i)\n",
        "            if torch.sum(idx) != 0:\n",
        "                acc_per_class[i] = torch.sum(test_label[idx]==predicted_label[idx]).float() / torch.sum(idx)\n",
        "        return acc_per_class.mean()\n",
        "\n",
        "    def compute_every_class_acc(self, test_label, predicted_label, nclass):\n",
        "        acc_per_class = torch.FloatTensor(nclass).fill_(0)\n",
        "        for i in range(nclass):\n",
        "            idx = (test_label == i)\n",
        "            if torch.sum(idx) != 0:\n",
        "                acc_per_class[i] = torch.sum(test_label[idx]==predicted_label[idx]).float() / torch.sum(idx)\n",
        "        return acc_per_class\n",
        "#util\n",
        "class LINEAR_LOGSOFTMAX(nn.Module):\n",
        "    def __init__(self, input_dim, nclass):\n",
        "        super(LINEAR_LOGSOFTMAX, self).__init__()\n",
        "        self.fc = nn.Linear(input_dim, nclass)\n",
        "        self.logic = nn.LogSoftmax(dim=1)\n",
        "    def forward(self, x): \n",
        "        o = self.logic(self.fc(x))\n",
        "        return o  "
      ],
      "execution_count": 72,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "QqE2U79MnTYz",
        "colab_type": "text"
      },
      "source": [
        "models.py"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "kzhb42YZnVRj",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "import torch.nn as nn\n",
        "import torch\n",
        "#MLP_G\n",
        "def weights_init(m):\n",
        "    classname = m.__class__.__name__\n",
        "    if classname.find('Linear') != -1:\n",
        "        m.weight.data.normal_(0.0, 0.02)\n",
        "        m.bias.data.fill_(0)\n",
        "    elif classname.find('BatchNorm') != -1:\n",
        "        m.weight.data.normal_(1.0, 0.02)\n",
        "        m.bias.data.fill_(0)\n",
        "\n",
        "class MLP_AC_D(nn.Module):\n",
        "    def __init__(self, opt): \n",
        "        super(MLP_AC_D, self).__init__()\n",
        "        self.fc1 = nn.Linear(opt.resSize, opt.ndh)\n",
        "        self.disc_linear = nn.Linear(opt.ndh, 1)\n",
        "        self.aux_linear = nn.Linear(opt.ndh, opt.attSize)\n",
        "        self.lrelu = nn.LeakyReLU(0.2, True)\n",
        "        self.sigmoid = nn.Sigmoid()\n",
        "\n",
        "        self.apply(weights_init)\n",
        "\n",
        "    def forward(self, x):\n",
        "        h = self.lrelu(self.fc1(x))\n",
        "        s = self.sigmoid(self.disc_linear(h))\n",
        "        a = self.aux_linear(h)\n",
        "        return s,a \n",
        "\n",
        "class MLP_AC_2HL_D(nn.Module):\n",
        "    def __init__(self, opt): \n",
        "        super(MLP_AC_2HL_D, self).__init__()\n",
        "        self.fc1 = nn.Linear(opt.resSize, opt.ndh)\n",
        "        self.fc2 = nn.Linear(opt.ndh, opt.ndh)\n",
        "        self.disc_linear = nn.Linear(opt.ndh, 1)\n",
        "        self.aux_linear = nn.Linear(opt.ndh, opt.attSize)\n",
        "        self.lrelu = nn.LeakyReLU(0.2, True)\n",
        "        self.sigmoid = nn.Sigmoid()\n",
        "        self.dropout = nn.Dropout(p=0.5)\n",
        "\n",
        "        self.apply(weights_init)\n",
        "\n",
        "    def forward(self, x):\n",
        "        h = self.dropout(self.lrelu(self.fc1(x)))\n",
        "        h = self.dropout(self.lrelu(self.fc2(h)))\n",
        "        s = self.sigmoid(self.disc_linear(h))\n",
        "        a = self.aux_linear(h)\n",
        "        return s,a \n",
        "\n",
        "class MLP_3HL_CRITIC(nn.Module):\n",
        "    def __init__(self, opt): \n",
        "        super(MLP_3HL_CRITIC, self).__init__()\n",
        "        self.fc1 = nn.Linear(opt.resSize + opt.attSize, opt.ndh)\n",
        "        self.fc2 = nn.Linear(opt.ndh, opt.ndh)\n",
        "        self.fc3 = nn.Linear(opt.ndh, opt.ndh)\n",
        "        self.fc4 = nn.Linear(opt.ndh, 1)\n",
        "        self.lrelu = nn.LeakyReLU(0.2, True)\n",
        "        self.apply(weights_init)\n",
        "\n",
        "    def forward(self, x, att):\n",
        "        h = torch.cat((x, att), 1) \n",
        "        h = self.lrelu(self.fc1(h))\n",
        "        h = self.lrelu(self.fc2(h))\n",
        "        h = self.lrelu(self.fc3(h))\n",
        "        h = self.fc4(h)\n",
        "        return h\n",
        "\n",
        "class MLP_2HL_CRITIC(nn.Module):\n",
        "    def __init__(self, opt): \n",
        "        super(MLP_2HL_CRITIC, self).__init__()\n",
        "        self.fc1 = nn.Linear(opt.resSize + opt.attSize, opt.ndh)\n",
        "        self.fc2 = nn.Linear(opt.ndh, opt.ndh)\n",
        "        self.fc3 = nn.Linear(opt.ndh, 1)\n",
        "        self.lrelu = nn.LeakyReLU(0.2, True)\n",
        "        self.apply(weights_init)\n",
        "\n",
        "    def forward(self, x, att):\n",
        "        h = torch.cat((x, att), 1) \n",
        "        h = self.lrelu(self.fc1(h))\n",
        "        h = self.lrelu(self.fc2(h))\n",
        "        h = self.fc3(h)\n",
        "        return h\n",
        "\n",
        "class MLP_2HL_Dropout_CRITIC(nn.Module):\n",
        "    def __init__(self, opt): \n",
        "        super(MLP_2HL_Dropout_CRITIC, self).__init__()\n",
        "        self.fc1 = nn.Linear(opt.resSize + opt.attSize, opt.ndh)\n",
        "        self.fc2 = nn.Linear(opt.ndh, opt.ndh)\n",
        "        self.fc3 = nn.Linear(opt.ndh, 1)\n",
        "        self.lrelu = nn.LeakyReLU(0.2, True)\n",
        "        self.dropout = nn.Dropout(p=0.5)\n",
        "        self.apply(weights_init)\n",
        "\n",
        "    def forward(self, x, att):\n",
        "        h = torch.cat((x, att), 1) \n",
        "        h = self.dropout(self.lrelu(self.fc1(h)))\n",
        "        h = self.dropout(self.lrelu(self.fc2(h)))\n",
        "        h = self.fc3(h)\n",
        "        return h\n",
        "\n",
        "class MLP_CRITIC(nn.Module):\n",
        "    def __init__(self, opt): \n",
        "        super(MLP_CRITIC, self).__init__()\n",
        "        self.fc1 = nn.Linear(opt.resSize + opt.attSize, opt.ndh)\n",
        "        #self.fc2 = nn.Linear(opt.ndh, opt.ndh)\n",
        "        self.fc2 = nn.Linear(opt.ndh, 1)\n",
        "        self.lrelu = nn.LeakyReLU(0.2, True)\n",
        "\n",
        "        self.apply(weights_init)\n",
        "\n",
        "    def forward(self, x, att):\n",
        "        h = torch.cat((x, att), 1) \n",
        "        h = self.lrelu(self.fc1(h))\n",
        "        h = self.fc2(h)\n",
        "        return h\n",
        "\n",
        "class MLP_D(nn.Module):\n",
        "    def __init__(self, opt): \n",
        "        super(MLP_D, self).__init__()\n",
        "        self.fc1 = nn.Linear(opt.resSize + opt.attSize, opt.ndh)\n",
        "        self.fc2 = nn.Linear(opt.ndh, 1)\n",
        "        self.lrelu = nn.LeakyReLU(0.2, True)\n",
        "        self.sigmoid = nn.Sigmoid()\n",
        "\n",
        "        self.apply(weights_init)\n",
        "\n",
        "    def forward(self, x, att):\n",
        "        h = torch.cat((x, att), 1) \n",
        "        h = self.lrelu(self.fc1(h))\n",
        "        h = self.sigmoid(self.fc2(h))\n",
        "        return h\n",
        "\n",
        "class MLP_2HL_Dropout_G(nn.Module):\n",
        "    def __init__(self, opt):\n",
        "        super(MLP_2HL_Dropout_G, self).__init__()\n",
        "        self.fc1 = nn.Linear(opt.attSize + opt.nz, opt.ngh)\n",
        "        self.fc2 = nn.Linear(opt.ngh, opt.ngh)\n",
        "        self.fc3 = nn.Linear(opt.ngh, opt.resSize)\n",
        "        self.lrelu = nn.LeakyReLU(0.2, True)\n",
        "        #self.prelu = nn.PReLU()\n",
        "        self.relu = nn.ReLU(True)\n",
        "        self.dropout = nn.Dropout(p=0.5)\n",
        "\n",
        "        self.apply(weights_init)\n",
        "\n",
        "    def forward(self, noise, att):\n",
        "        h = torch.cat((noise, att), 1)\n",
        "        h = self.dropout(self.lrelu(self.fc1(h)))\n",
        "        h = self.dropout(self.lrelu(self.fc2(h)))\n",
        "        h = self.relu(self.fc3(h))\n",
        "        return h\n",
        "\n",
        "class MLP_3HL_G(nn.Module):\n",
        "    def __init__(self, opt):\n",
        "        super(MLP_3HL_G, self).__init__()\n",
        "        self.fc1 = nn.Linear(opt.attSize + opt.nz, opt.ngh)\n",
        "        self.fc2 = nn.Linear(opt.ngh, opt.ngh)\n",
        "        self.fc3 = nn.Linear(opt.ngh, opt.ngh)\n",
        "        self.fc4 = nn.Linear(opt.ngh, opt.resSize)\n",
        "        self.lrelu = nn.LeakyReLU(0.2, True)\n",
        "        #self.prelu = nn.PReLU()\n",
        "        self.relu = nn.ReLU(True)\n",
        "\n",
        "        self.apply(weights_init)\n",
        "\n",
        "    def forward(self, noise, att):\n",
        "        h = torch.cat((noise, att), 1)\n",
        "        h = self.lrelu(self.fc1(h))\n",
        "        h = self.lrelu(self.fc2(h))\n",
        "        h = self.lrelu(self.fc3(h))\n",
        "        h = self.relu(self.fc4(h))\n",
        "        return h\n",
        "\n",
        "class MLP_2HL_G(nn.Module):\n",
        "    def __init__(self, opt):\n",
        "        super(MLP_2HL_G, self).__init__()\n",
        "        self.fc1 = nn.Linear(opt.attSize + opt.nz, opt.ngh)\n",
        "        self.fc2 = nn.Linear(opt.ngh, opt.ngh)\n",
        "        self.fc3 = nn.Linear(opt.ngh, opt.resSize)\n",
        "        self.lrelu = nn.LeakyReLU(0.2, True)\n",
        "        #self.prelu = nn.PReLU()\n",
        "        self.relu = nn.ReLU(True)\n",
        "\n",
        "        self.apply(weights_init)\n",
        "\n",
        "    def forward(self, noise, att):\n",
        "        h = torch.cat((noise, att), 1)\n",
        "        h = self.lrelu(self.fc1(h))\n",
        "        h = self.lrelu(self.fc2(h))\n",
        "        h = self.relu(self.fc3(h))\n",
        "        return h\n",
        "\n",
        "class MLP_Dropout_G(nn.Module):\n",
        "    def __init__(self, opt):\n",
        "        super(MLP_Dropout_G, self).__init__()\n",
        "        self.fc1 = nn.Linear(opt.attSize + opt.nz, opt.ngh)\n",
        "        self.fc2 = nn.Linear(opt.ngh, opt.resSize)\n",
        "        self.lrelu = nn.LeakyReLU(0.2, True)\n",
        "        self.relu = nn.ReLU(True)\n",
        "        self.dropout = nn.Dropout(p=0.2)\n",
        "\n",
        "        self.apply(weights_init)\n",
        "\n",
        "    def forward(self, noise, att):\n",
        "        h = torch.cat((noise, att), 1)\n",
        "        h = self.dropout(self.lrelu(self.fc1(h)))\n",
        "        h = self.relu(self.fc2(h))\n",
        "        return h\n",
        "\n",
        "class MLP_G(nn.Module):\n",
        "    def __init__(self, opt):\n",
        "        super(MLP_G, self).__init__()\n",
        "        self.fc1 = nn.Linear(opt.attSize + opt.nz, opt.ngh)\n",
        "        self.fc2 = nn.Linear(opt.ngh, opt.resSize)\n",
        "        self.lrelu = nn.LeakyReLU(0.2, True)\n",
        "        #self.prelu = nn.PReLU()\n",
        "        self.relu = nn.ReLU(True)\n",
        "\n",
        "        self.apply(weights_init)\n",
        "\n",
        "    def forward(self, noise, att):\n",
        "        h = torch.cat((noise, att), 1)\n",
        "        h = self.lrelu(self.fc1(h))\n",
        "        h = self.relu(self.fc2(h))\n",
        "        return h\n",
        "\n",
        "class MLP_2048_1024_Dropout_G(nn.Module):\n",
        "    def __init__(self, opt):\n",
        "        super(MLP_2048_1024_Dropout_G, self).__init__()\n",
        "        self.fc1 = nn.Linear(opt.attSize + opt.nz, opt.ngh)\n",
        "        #self.fc2 = nn.Linear(opt.ngh, opt.ngh)\n",
        "        self.fc2 = nn.Linear(opt.ngh, 1024)\n",
        "        self.fc3 = nn.Linear(1024, opt.resSize)\n",
        "        self.lrelu = nn.LeakyReLU(0.2, True)\n",
        "        #self.prelu = nn.PReLU()\n",
        "        #self.relu = nn.ReLU(True)\n",
        "        self.dropout = nn.Dropout(p=0.5)\n",
        "\n",
        "        self.apply(weights_init)\n",
        "\n",
        "    def forward(self, noise, att):\n",
        "        h = torch.cat((noise, att), 1)\n",
        "        h = self.dropout(self.lrelu(self.fc1(h)))\n",
        "        h = self.dropout(self.lrelu(self.fc2(h)))\n",
        "        h = self.fc3(h)\n",
        "        return h\n",
        "\n",
        "\n",
        "class MLP_SKIP_G(nn.Module):\n",
        "    def __init__(self, opt):\n",
        "        super(MLP_SKIP_G, self).__init__()\n",
        "        self.fc1 = nn.Linear(opt.attSize + opt.nz, opt.ngh)\n",
        "        #self.fc2 = nn.Linear(opt.ngh, opt.ngh)\n",
        "        #self.fc2 = nn.Linear(opt.ngh, 1024)\n",
        "        self.fc2 = nn.Linear(opt.ngh, opt.resSize)\n",
        "        self.fc_skip = nn.Linear(opt.attSize, opt.resSize)\n",
        "        self.lrelu = nn.LeakyReLU(0.2, True)\n",
        "        #self.prelu = nn.PReLU()\n",
        "        self.relu = nn.ReLU(True)\n",
        "        \n",
        "        self.apply(weights_init)\n",
        "\n",
        "    def forward(self, noise, att):\n",
        "        h = torch.cat((noise, att), 1)\n",
        "        h = self.lrelu(self.fc1(h))\n",
        "        #h = self.lrelu(self.fc2(h))\n",
        "        h = self.relu(self.fc2(h))\n",
        "        h2 = self.fc_skip(att)\n",
        "        return h+h2\n",
        "\n",
        "\n",
        "#util\n",
        "class MLP_SKIP_D(nn.Module):\n",
        "    def __init__(self, opt): \n",
        "        super(MLP_SKIP_D, self).__init__()\n",
        "        self.fc1 = nn.Linear(opt.resSize + opt.attSize, opt.ndh)\n",
        "        self.fc2 = nn.Linear(opt.ndh, 1)\n",
        "        self.fc_skip = nn.Linear(opt.attSize, opt.ndh)\n",
        "        self.lrelu = nn.LeakyReLU(0.2, True)\n",
        "        self.sigmoid = nn.Sigmoid()\n",
        "\n",
        "        self.apply(weights_init)\n",
        "    \n",
        "    def forward(self, x, att):\n",
        "        h = torch.cat((x, att), 1) \n",
        "        h = self.lrelu(self.fc1(h))\n",
        "        h2 = self.lrelu(self.fc_skip(att))\n",
        "        h = self.sigmoid(self.fc2(h+h2))\n",
        "        return h"
      ],
      "execution_count": 73,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5yEQ9H9inBnU",
        "colab_type": "text"
      },
      "source": [
        "# lisgan.py"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "XZc02z3HnKFd",
        "colab_type": "code",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 1000
        },
        "outputId": "0bf832e2-78da-45cd-fa01-b90471e1d4cf"
      },
      "source": [
        "from __future__ import print_function\n",
        "import argparse\n",
        "import os\n",
        "import random\n",
        "import torch\n",
        "import torch.nn as nn\n",
        "import torch.autograd as autograd\n",
        "import torch.optim as optim\n",
        "import torch.backends.cudnn as cudnn\n",
        "from torch.autograd import Variable\n",
        "import math\n",
        "import sys\n",
        "import numpy as np\n",
        "import time\n",
        "import torch.nn.functional as F\n",
        "from sklearn.cluster import KMeans\n",
        "\n",
        "class parser:\n",
        "  pass\n",
        "parser.dataset='AWA2'\n",
        "parser.dataroot='/content/drive/My Drive/Colab Notebooks/Project/xlsa17/data'\n",
        "parser.matdataset=True\n",
        "parser.image_embedding='res101'\n",
        "parser.class_embedding='att'\n",
        "parser.syn_num=100  \n",
        "parser.gzsl=True #False\n",
        "parser.preprocessing=False,\n",
        "parser.standardization=False\n",
        "parser.validation=False\n",
        "parser.workers=2\n",
        "parser.batch_size=64\n",
        "parser.resSize=2048\n",
        "parser.attSize=85 #1024\n",
        "parser.nz= 85 #312\n",
        "parser.ngh=4096\n",
        "parser.ndh=1024\n",
        "parser.nepoch=100\n",
        "parser.critic_iter=5\n",
        "parser.lambda1=10\n",
        "parser.cls_weight=1\n",
        "parser.lr=0.0001\n",
        "parser.classifier_lr=0.001\n",
        "parser.beta1=0.5\n",
        "parser.cuda=True\n",
        "parser.ngpu=1\n",
        "parser.pretrain_classifier=''\n",
        "parser.netG=''\n",
        "parser.netD=''\n",
        "parser.netG_name=''\n",
        "parser.netD_name=''\n",
        "parser.outf='./checkpoint/'\n",
        "#parser.('--outname', help='folder to output data and model checkpoints')\n",
        "parser.save_every=100\n",
        "parser.print_every=1\n",
        "parser.val_every=10\n",
        "parser.start_epoch=0\n",
        "#parser.manualSeed', type=int, help='manual seed')\n",
        "parser.nclass_all=50 #200\n",
        "parser.ratio=0.2\n",
        "parser.proto_param1=0.01\n",
        "parser.proto_param2=0.01\n",
        "parser.loss_syn_num=20\n",
        "parser.n_clusters=3\n",
        "\n",
        "\n",
        "def GetNowTime():\n",
        "    return time.strftime(\"%Y-%m-%d %H:%M:%S\", time.localtime(time.time()))\n",
        "\n",
        "print(GetNowTime())\n",
        "print('Begin run!!!')\n",
        "since = time.time()\n",
        "\n",
        "opt = parser()\n",
        "print('Params: dataset={:s}, GZSL={:s}, ratio={:.1f}, cls_weight={:.4f}, proto_param1={:.4f}, proto_param2={:.4f}'.format(\n",
        "    opt.dataset, str(opt.gzsl), opt.ratio, opt.cls_weight,opt.proto_param1, opt.proto_param2))\n",
        "sys.stdout.flush()\n",
        "\n",
        "'''\n",
        "if opt.manualSeed is None:\n",
        "    opt.manualSeed = random.randint(1, 10000)\n",
        "print(\"Random Seed: \", opt.manualSeed)\n",
        "random.seed(opt.manualSeed)\n",
        "torch.manual_seed(opt.manualSeed)\n",
        "if opt.cuda:\n",
        "    torch.cuda.manual_seed_all(opt.manualSeed)\n",
        "'''\n",
        "cudnn.benchmark = True\n",
        "\n",
        "if torch.cuda.is_available() and not opt.cuda:\n",
        "    print(\"WARNING: You have a CUDA device, so you should probably run with --cuda\")\n",
        "\n",
        "# load data\n",
        "data = DATA_LOADER(opt)\n",
        "print(\"Training samples: \", data.ntrain)\n",
        "#util\n",
        "# initialize generator and discriminator\n",
        "netG = MLP_G(opt)\n",
        "if opt.netG != '':\n",
        "    netG.load_state_dict(torch.load(opt.netG))\n",
        "# print(netG)\n",
        "#classifier\n",
        "netD = MLP_CRITIC(opt)\n",
        "if opt.netD != '':\n",
        "    netD.load_state_dict(torch.load(opt.netD))\n",
        "# print(netD)\n",
        "\n",
        "# classification loss, Equation (4) of the paper\n",
        "cls_criterion = nn.NLLLoss()\n",
        "\n",
        "input_res = torch.FloatTensor(opt.batch_size, opt.resSize)\n",
        "input_att = torch.FloatTensor(opt.batch_size, opt.attSize)\n",
        "noise = torch.FloatTensor(opt.batch_size, opt.nz)\n",
        "one = torch.FloatTensor([1])\n",
        "mone = one * -1\n",
        "input_label = torch.LongTensor(opt.batch_size)\n",
        "\n",
        "if torch.cuda:\n",
        "    netD.cuda()\n",
        "    netG.cuda()\n",
        "    input_res = input_res.cuda()\n",
        "    noise, input_att = noise.cuda(), input_att.cuda()\n",
        "    one = one.cuda()\n",
        "    mone = mone.cuda()\n",
        "    cls_criterion.cuda()\n",
        "    input_label = input_label.cuda()\n",
        "\n",
        "#classifier\n",
        "def sample():\n",
        "    batch_feature, batch_label, batch_att = data.next_batch(opt.batch_size)\n",
        "    input_res.copy_(batch_feature)\n",
        "    input_att.copy_(batch_att)\n",
        "    input_label.copy_(map_label(batch_label, data.seenclasses))\n",
        "\n",
        "\n",
        "def generate_syn_feature(netG, classes, attribute, num):\n",
        "    nclass = classes.size(0)\n",
        "    syn_feature = torch.FloatTensor(nclass * num, opt.resSize)\n",
        "    syn_label = torch.LongTensor(nclass * num)\n",
        "    syn_att = torch.FloatTensor(num, opt.attSize)\n",
        "    syn_noise = torch.FloatTensor(num, opt.nz)\n",
        "    if torch.cuda:\n",
        "        syn_att = syn_att.cuda()\n",
        "        syn_noise = syn_noise.cuda()\n",
        "\n",
        "    for i in range(nclass):\n",
        "        iclass = classes[i]\n",
        "        iclass_att = attribute[iclass]\n",
        "        syn_att.copy_(iclass_att.repeat(num, 1))\n",
        "        syn_noise.normal_(0, 1)\n",
        "        output = netG(Variable(syn_noise, volatile=True), Variable(syn_att, volatile=True))\n",
        "        syn_feature.narrow(0, i * num, num).copy_(output.data.cpu())\n",
        "        syn_label.narrow(0, i * num, num).fill_(iclass)\n",
        "\n",
        "    return syn_feature, syn_label\n",
        "\n",
        "def generate_syn_feature_with_grad(netG, classes, attribute, num):\n",
        "    nclass = classes.size(0)\n",
        "    # syn_feature = torch.FloatTensor(nclass*num, opt.resSize)\n",
        "    syn_label = torch.LongTensor(nclass * num)\n",
        "    syn_att = torch.FloatTensor(nclass * num, opt.attSize)\n",
        "    syn_noise = torch.FloatTensor(nclass * num, opt.nz)\n",
        "    if torch.cuda:\n",
        "        syn_att = syn_att.cuda()\n",
        "        syn_noise = syn_noise.cuda()\n",
        "        syn_label = syn_label.cuda()\n",
        "    syn_noise.normal_(0, 1)\n",
        "    for i in range(nclass):\n",
        "        iclass = classes[i]\n",
        "        iclass_att = attribute[iclass]\n",
        "        syn_att.narrow(0, i * num, num).copy_(iclass_att.repeat(num, 1))\n",
        "        syn_label.narrow(0, i * num, num).fill_(iclass)\n",
        "    syn_feature = netG(Variable(syn_noise), Variable(syn_att))\n",
        "    return syn_feature, syn_label.cpu()\n",
        "\n",
        "def map_label(label, classes):\n",
        "    mapped_label = torch.LongTensor(label.size())\n",
        "    for i in range(classes.size(0)):\n",
        "        mapped_label[label==classes[i]] = i\n",
        "    return mapped_label\n",
        "#util\n",
        "\n",
        "def pairwise_distances(x, y=None):\n",
        "    '''\n",
        "    Input: x is a Nxd matrix\n",
        "           y is an optional Mxd matirx\n",
        "    Output: dist is a NxM matrix where dist[i,j] is the square norm between x[i,:] and y[j,:]\n",
        "            if y is not given then use 'y=x'.\n",
        "    i.e. dist[i,j] = ||x[i,:]-y[j,:]||^2\n",
        "    '''\n",
        "    x_norm = (x ** 2).sum(1).view(-1, 1)\n",
        "    if y is not None:\n",
        "        y_t = torch.transpose(y, 0, 1)\n",
        "        y_norm = (y ** 2).sum(1).view(1, -1)\n",
        "    else:\n",
        "        y_t = torch.transpose(x, 0, 1)\n",
        "        y_norm = x_norm.view(1, -1)\n",
        "\n",
        "    dist = x_norm + y_norm - 2.0 * torch.mm(x, y_t)\n",
        "    # Ensure diagonal is zero if x=y\n",
        "    if y is None:\n",
        "        dist = dist - torch.diag(dist.diag)\n",
        "    return torch.clamp(dist, 0.0, np.inf)\n",
        "\n",
        "# setup optimizer\n",
        "optimizerD = optim.Adam(netD.parameters(), lr=opt.lr, betas=(opt.beta1, 0.999))\n",
        "optimizerG = optim.Adam(netG.parameters(), lr=opt.lr, betas=(opt.beta1, 0.999))\n",
        "\n",
        "\n",
        "def calc_gradient_penalty(netD, real_data, fake_data, input_att):\n",
        "    # print real_data.size()\n",
        "    alpha = torch.rand(opt.batch_size, 1)\n",
        "    alpha = alpha.expand(real_data.size())\n",
        "    if torch.cuda:\n",
        "        alpha = alpha.cuda()\n",
        "\n",
        "    interpolates = alpha * real_data + ((1 - alpha) * fake_data)\n",
        "\n",
        "    if torch.cuda:\n",
        "        interpolates = interpolates.cuda()\n",
        "\n",
        "    interpolates = Variable(interpolates, requires_grad=True)\n",
        "\n",
        "    disc_interpolates = netD(interpolates, Variable(input_att))\n",
        "\n",
        "    ones = torch.ones(disc_interpolates.size())\n",
        "    if torch.cuda:\n",
        "        ones = ones.cuda()\n",
        "\n",
        "    gradients = autograd.grad(outputs=disc_interpolates, inputs=interpolates,\n",
        "                              grad_outputs=ones,\n",
        "                              create_graph=True, retain_graph=True, only_inputs=True)[0]\n",
        "\n",
        "    gradient_penalty = ((gradients.norm(2, dim=1) - 1) ** 2).mean() * opt.lambda1\n",
        "    return gradient_penalty\n",
        "\n",
        "\n",
        "# train a classifier on seen classes, obtain \\theta of Equation (4)\n",
        "pretrain_cls = CLASSIFIER(data.train_feature, map_label(data.train_label, data.seenclasses),\n",
        "                                     data.seenclasses.size(0), opt.resSize, opt.cuda, 0.001, 0.5, 100, 100,\n",
        "                                     opt.pretrain_classifier)\n",
        "\n",
        "# freeze the classifier during the optimization\n",
        "'''\n",
        "for p in pretrain_cls.parameters():  # set requires_grad to False\n",
        "    p.requires_grad = False\n",
        "'''\n",
        "#classifier\n",
        "for epoch in range(opt.nepoch):\n",
        "    FP = 0\n",
        "    mean_lossD = 0\n",
        "    mean_lossG = 0\n",
        "\n",
        "    for i in range(0, data.ntrain, opt.batch_size):\n",
        "\n",
        "        for p in netD.parameters():\n",
        "            p.requires_grad = True\n",
        "\n",
        "        for iter_d in range(opt.critic_iter):\n",
        "            sample()\n",
        "            netD.zero_grad()\n",
        "            sparse_real = opt.resSize - input_res[1].gt(0).sum()\n",
        "            input_resv = Variable(input_res)\n",
        "            input_attv = Variable(input_att)\n",
        "\n",
        "            criticD_real = netD(input_resv, input_attv)\n",
        "            criticD_real = criticD_real.mean()\n",
        "            criticD_real.backward(mone)\n",
        "\n",
        "            noise.normal_(0, 1)\n",
        "            noisev = Variable(noise)\n",
        "            fake = netG(noisev, input_attv)\n",
        "            fake_norm = fake.data[0].norm()\n",
        "            sparse_fake = fake.data[0].eq(0).sum()\n",
        "            criticD_fake = netD(fake.detach(), input_attv)\n",
        "            criticD_fake = criticD_fake.mean()\n",
        "            criticD_fake.backward(one)\n",
        "\n",
        "            gradient_penalty = calc_gradient_penalty(netD, input_res, fake.data, input_att)\n",
        "            gradient_penalty.backward()\n",
        "\n",
        "            Wasserstein_D = criticD_real - criticD_fake\n",
        "            D_cost = criticD_fake - criticD_real + gradient_penalty\n",
        "            optimizerD.step()\n",
        "\n",
        "        for p in netD.parameters():  # reset requires_grad\n",
        "            p.requires_grad = False  # avoid computation\n",
        "\n",
        "        netG.zero_grad()\n",
        "        input_attv = Variable(input_att)\n",
        "        noise.normal_(0, 1)\n",
        "        noisev = Variable(noise)\n",
        "        fake = netG(noisev, input_attv)\n",
        "        criticG_fake = netD(fake, input_attv)\n",
        "        criticG_fake = criticG_fake.mean()\n",
        "        G_cost = -criticG_fake\n",
        "        # classification loss\n",
        "        #print(pretrain_cls, \"pretrain_cls\")\n",
        "        #print(input_label, \"input_label\")\n",
        "        #print(Variable(input_label), \"Variable(input_label)\")\n",
        "        c_errG = cls_criterion(fake, Variable(input_label))\n",
        "\n",
        "        labels = Variable(input_label.view(opt.batch_size, 1))\n",
        "        real_proto = Variable(data.real_proto.cuda())\n",
        "        dists1 = pairwise_distances(fake,real_proto)\n",
        "        min_idx1 = torch.zeros(opt.batch_size, data.train_cls_num)\n",
        "        for i in range(data.train_cls_num):\n",
        "            min_idx1[:,i] = torch.min(dists1.data[:,i*opt.n_clusters:(i+1)*opt.n_clusters],dim=1)[1] + i*opt.n_clusters\n",
        "        min_idx1 = Variable(min_idx1.long().cuda())\n",
        "        loss2 = dists1.gather(1,min_idx1).gather(1,labels).squeeze().view(-1).mean()\n",
        "\n",
        "        seen_feature, seen_label = generate_syn_feature_with_grad(netG, data.seenclasses, data.attribute,opt.loss_syn_num)\n",
        "        seen_mapped_label = map_label(seen_label, data.seenclasses)\n",
        "        transform_matrix = torch.zeros(data.train_cls_num, seen_feature.size(0))  # 150x7057\n",
        "        for i in range(data.train_cls_num):\n",
        "            sample_idx = (seen_mapped_label == i).nonzero().squeeze()\n",
        "            if sample_idx.numel() == 0:\n",
        "                continue\n",
        "            else:\n",
        "                cls_fea_num = sample_idx.numel()\n",
        "                transform_matrix[i][sample_idx] = 1 / cls_fea_num * torch.ones(1, cls_fea_num).squeeze()\n",
        "        transform_matrix = Variable(transform_matrix.cuda())\n",
        "        fake_proto = torch.mm(transform_matrix, seen_feature)  # 150x2048\n",
        "        dists2 = pairwise_distances(fake_proto,Variable(data.real_proto.cuda())) # 150 x 450\n",
        "        min_idx2 = torch.zeros(data.train_cls_num, data.train_cls_num)\n",
        "        for i in range(data.train_cls_num):\n",
        "            min_idx2[:,i] = torch.min(dists2.data[:,i*opt.n_clusters:(i+1)*opt.n_clusters],dim=1)[1] + i*opt.n_clusters\n",
        "        min_idx2 = Variable(min_idx2.long().cuda())\n",
        "        lbl_idx = Variable(torch.LongTensor(list(range(data.train_cls_num))).cuda())\n",
        "        loss1 = dists2.gather(1,min_idx2).gather(1,lbl_idx.unsqueeze(1)).squeeze().mean()\n",
        "\n",
        "        errG = G_cost + opt.cls_weight * c_errG + opt.proto_param2 * loss2 + opt.proto_param1 * loss1\n",
        "        errG.backward()\n",
        "        optimizerG.step()\n",
        "\n",
        "    print('EP[%d/%d]************************************************************************************' % (\n",
        "    epoch, opt.nepoch))\n",
        "\n",
        "    # evaluate the model, set G to evaluation mode\n",
        "    netG.eval()\n",
        "    # Generalized zero-shot learning\n",
        "    if opt.gzsl:\n",
        "        syn_feature, syn_label = generate_syn_feature(netG, data.unseenclasses, data.attribute, opt.syn_num)\n",
        "        train_X = torch.cat((data.train_feature, syn_feature), 0)\n",
        "        train_Y = torch.cat((data.train_label, syn_label), 0)\n",
        "        nclass = opt.nclass_all\n",
        "        cls = CLASSIFIER2(train_X, train_Y, data, nclass, opt.cuda, opt.classifier_lr, 0.5, 50, 2*opt.syn_num,True)\n",
        "        print('unseen=%.4f, seen=%.4f, h=%.4f' % (cls.acc_unseen, cls.acc_seen, cls.H))\n",
        "    # Zero-shot learning\n",
        "    else:\n",
        "        syn_feature, syn_label = generate_syn_feature(netG, data.unseenclasses, data.attribute, opt.syn_num)\n",
        "        cls = CLASSIFIER2(syn_feature, map_label(syn_label, data.unseenclasses), data,\n",
        "                                     data.unseenclasses.size(0), opt.cuda, opt.classifier_lr, 0.5, 50, 2*opt.syn_num,\n",
        "                                     False, opt.ratio, epoch)\n",
        "        acc = cls.acc \n",
        "        print('unseen class accuracy= ', int(cls.acc)*100, \"%\")\n",
        "    del cls\n",
        "    cls = None\n",
        "    # reset G to training mode\n",
        "    netG.train()\n",
        "    sys.stdout.flush()\n",
        "\n",
        "time_elapsed = time.time() - since\n",
        "print('End run!!!')\n",
        "print('Time Elapsed: {}'.format(time_elapsed))\n",
        "print(GetNowTime())"
      ],
      "execution_count": 74,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "2020-09-20 11:52:26\n",
            "Begin run!!!\n",
            "Params: dataset=AWA2, GZSL=True, ratio=0.2, cls_weight=1.0000, proto_param1=0.0100, proto_param2=0.0100\n",
            "Training samples:  23527\n",
            "EP[0/100]************************************************************************************\n"
          ],
          "name": "stdout"
        },
        {
          "output_type": "stream",
          "text": [
            "/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:150: UserWarning: volatile was removed and now has no effect. Use `with torch.no_grad():` instead.\n",
            "/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:383: UserWarning: volatile was removed and now has no effect. Use `with torch.no_grad():` instead.\n"
          ],
          "name": "stderr"
        },
        {
          "output_type": "stream",
          "text": [
            "First Seen: 78.96%, Unseen: 0.00%, First H: 0.00%\n",
            "1NN   Seen: 81.59%, Unseen: 0.00%, 1NN H: 0.00%\n",
            "FC    Seen: 83.47%, Unseen: 0.00%, FC H: 0.00%\n",
            "unseen=0.0000, seen=0.8347, h=0.0000\n",
            "EP[1/100]************************************************************************************\n",
            "First Seen: 92.35%, Unseen: 1.55%, First H: 3.05%\n",
            "1NN   Seen: 90.33%, Unseen: 0.08%, 1NN H: 0.16%\n",
            "FC    Seen: 91.92%, Unseen: 0.13%, FC H: 0.26%\n",
            "unseen=0.0013, seen=0.9192, h=0.0026\n",
            "EP[2/100]************************************************************************************\n",
            "First Seen: 92.55%, Unseen: 1.81%, First H: 3.56%\n",
            "1NN   Seen: 90.63%, Unseen: 0.18%, 1NN H: 0.35%\n",
            "FC    Seen: 92.57%, Unseen: 0.17%, FC H: 0.35%\n",
            "unseen=0.0017, seen=0.9257, h=0.0035\n",
            "EP[3/100]************************************************************************************\n",
            "First Seen: 92.46%, Unseen: 1.16%, First H: 2.29%\n",
            "1NN   Seen: 90.41%, Unseen: 0.18%, 1NN H: 0.37%\n",
            "FC    Seen: 92.05%, Unseen: 0.11%, FC H: 0.23%\n",
            "unseen=0.0011, seen=0.9205, h=0.0023\n",
            "EP[4/100]************************************************************************************\n",
            "First Seen: 91.90%, Unseen: 1.84%, First H: 3.61%\n",
            "1NN   Seen: 90.40%, Unseen: 0.81%, 1NN H: 1.61%\n",
            "FC    Seen: 91.93%, Unseen: 0.69%, FC H: 1.38%\n",
            "unseen=0.0069, seen=0.9193, h=0.0138\n",
            "EP[5/100]************************************************************************************\n",
            "First Seen: 90.92%, Unseen: 1.51%, First H: 2.98%\n",
            "1NN   Seen: 89.39%, Unseen: 1.46%, 1NN H: 2.87%\n",
            "FC    Seen: 92.03%, Unseen: 0.92%, FC H: 1.82%\n",
            "unseen=0.0092, seen=0.9203, h=0.0182\n",
            "EP[6/100]************************************************************************************\n",
            "First Seen: 91.79%, Unseen: 1.05%, First H: 2.08%\n",
            "1NN   Seen: 89.91%, Unseen: 0.33%, 1NN H: 0.65%\n",
            "FC    Seen: 91.90%, Unseen: 0.14%, FC H: 0.28%\n",
            "unseen=0.0014, seen=0.9190, h=0.0028\n",
            "EP[7/100]************************************************************************************\n",
            "First Seen: 90.53%, Unseen: 0.83%, First H: 1.65%\n",
            "1NN   Seen: 88.96%, Unseen: 0.81%, 1NN H: 1.62%\n",
            "FC    Seen: 91.62%, Unseen: 0.34%, FC H: 0.68%\n",
            "unseen=0.0034, seen=0.9162, h=0.0068\n",
            "EP[8/100]************************************************************************************\n",
            "First Seen: 92.49%, Unseen: 1.51%, First H: 2.97%\n",
            "1NN   Seen: 90.18%, Unseen: 0.58%, 1NN H: 1.15%\n",
            "FC    Seen: 92.23%, Unseen: 0.33%, FC H: 0.65%\n",
            "unseen=0.0033, seen=0.9223, h=0.0065\n",
            "EP[9/100]************************************************************************************\n",
            "First Seen: 92.17%, Unseen: 0.94%, First H: 1.86%\n",
            "1NN   Seen: 90.02%, Unseen: 0.27%, 1NN H: 0.54%\n",
            "FC    Seen: 92.12%, Unseen: 0.14%, FC H: 0.27%\n",
            "unseen=0.0014, seen=0.9212, h=0.0027\n",
            "EP[10/100]************************************************************************************\n",
            "First Seen: 92.60%, Unseen: 0.96%, First H: 1.91%\n",
            "1NN   Seen: 90.49%, Unseen: 0.31%, 1NN H: 0.62%\n",
            "FC    Seen: 92.19%, Unseen: 0.10%, FC H: 0.20%\n",
            "unseen=0.0010, seen=0.9219, h=0.0020\n",
            "EP[11/100]************************************************************************************\n",
            "First Seen: 92.40%, Unseen: 0.97%, First H: 1.93%\n",
            "1NN   Seen: 90.42%, Unseen: 1.04%, 1NN H: 2.06%\n",
            "FC    Seen: 92.02%, Unseen: 0.39%, FC H: 0.78%\n",
            "unseen=0.0039, seen=0.9202, h=0.0078\n",
            "EP[12/100]************************************************************************************\n",
            "First Seen: 92.48%, Unseen: 0.81%, First H: 1.60%\n",
            "1NN   Seen: 90.50%, Unseen: 0.37%, 1NN H: 0.75%\n",
            "FC    Seen: 92.30%, Unseen: 0.22%, FC H: 0.45%\n",
            "unseen=0.0022, seen=0.9230, h=0.0045\n",
            "EP[13/100]************************************************************************************\n",
            "First Seen: 91.40%, Unseen: 0.58%, First H: 1.16%\n",
            "1NN   Seen: 89.30%, Unseen: 0.22%, 1NN H: 0.43%\n",
            "FC    Seen: 91.63%, Unseen: 0.17%, FC H: 0.33%\n",
            "unseen=0.0017, seen=0.9163, h=0.0033\n",
            "EP[14/100]************************************************************************************\n",
            "First Seen: 92.35%, Unseen: 0.97%, First H: 1.91%\n",
            "1NN   Seen: 90.16%, Unseen: 0.29%, 1NN H: 0.58%\n",
            "FC    Seen: 91.94%, Unseen: 0.15%, FC H: 0.29%\n",
            "unseen=0.0015, seen=0.9194, h=0.0029\n",
            "EP[15/100]************************************************************************************\n",
            "First Seen: 92.37%, Unseen: 1.25%, First H: 2.46%\n",
            "1NN   Seen: 90.69%, Unseen: 0.59%, 1NN H: 1.17%\n",
            "FC    Seen: 92.00%, Unseen: 0.26%, FC H: 0.52%\n",
            "unseen=0.0026, seen=0.9200, h=0.0052\n",
            "EP[16/100]************************************************************************************\n",
            "First Seen: 92.17%, Unseen: 0.79%, First H: 1.57%\n",
            "1NN   Seen: 89.97%, Unseen: 0.64%, 1NN H: 1.27%\n",
            "FC    Seen: 91.83%, Unseen: 0.38%, FC H: 0.75%\n",
            "unseen=0.0038, seen=0.9183, h=0.0075\n",
            "EP[17/100]************************************************************************************\n",
            "First Seen: 92.12%, Unseen: 0.38%, First H: 0.75%\n",
            "1NN   Seen: 89.99%, Unseen: 0.16%, 1NN H: 0.33%\n",
            "FC    Seen: 92.11%, Unseen: 0.04%, FC H: 0.08%\n",
            "unseen=0.0004, seen=0.9211, h=0.0008\n",
            "EP[18/100]************************************************************************************\n",
            "First Seen: 92.48%, Unseen: 0.54%, First H: 1.07%\n",
            "1NN   Seen: 90.71%, Unseen: 0.35%, 1NN H: 0.69%\n",
            "FC    Seen: 92.12%, Unseen: 0.13%, FC H: 0.26%\n",
            "unseen=0.0013, seen=0.9212, h=0.0026\n",
            "EP[19/100]************************************************************************************\n",
            "First Seen: 92.20%, Unseen: 0.72%, First H: 1.43%\n",
            "1NN   Seen: 90.05%, Unseen: 0.72%, 1NN H: 1.42%\n",
            "FC    Seen: 92.04%, Unseen: 0.41%, FC H: 0.82%\n",
            "unseen=0.0041, seen=0.9204, h=0.0082\n",
            "EP[20/100]************************************************************************************\n",
            "First Seen: 92.02%, Unseen: 0.42%, First H: 0.83%\n",
            "1NN   Seen: 89.70%, Unseen: 0.29%, 1NN H: 0.57%\n",
            "FC    Seen: 91.93%, Unseen: 0.08%, FC H: 0.16%\n",
            "unseen=0.0008, seen=0.9193, h=0.0016\n",
            "EP[21/100]************************************************************************************\n",
            "First Seen: 91.40%, Unseen: 0.30%, First H: 0.60%\n",
            "1NN   Seen: 89.45%, Unseen: 0.23%, 1NN H: 0.47%\n",
            "FC    Seen: 91.75%, Unseen: 0.02%, FC H: 0.04%\n",
            "unseen=0.0002, seen=0.9175, h=0.0004\n",
            "EP[22/100]************************************************************************************\n",
            "First Seen: 90.97%, Unseen: 0.40%, First H: 0.79%\n",
            "1NN   Seen: 89.29%, Unseen: 0.25%, 1NN H: 0.50%\n",
            "FC    Seen: 91.67%, Unseen: 0.11%, FC H: 0.21%\n",
            "unseen=0.0011, seen=0.9167, h=0.0021\n",
            "EP[23/100]************************************************************************************\n",
            "First Seen: 92.13%, Unseen: 0.20%, First H: 0.40%\n",
            "1NN   Seen: 90.01%, Unseen: 0.16%, 1NN H: 0.32%\n",
            "FC    Seen: 91.89%, Unseen: 0.01%, FC H: 0.02%\n",
            "unseen=0.0001, seen=0.9189, h=0.0002\n",
            "EP[24/100]************************************************************************************\n",
            "First Seen: 91.41%, Unseen: 0.45%, First H: 0.90%\n",
            "1NN   Seen: 89.43%, Unseen: 0.52%, 1NN H: 1.03%\n",
            "FC    Seen: 91.75%, Unseen: 0.01%, FC H: 0.01%\n",
            "unseen=0.0001, seen=0.9175, h=0.0001\n",
            "EP[25/100]************************************************************************************\n",
            "First Seen: 92.28%, Unseen: 0.41%, First H: 0.81%\n",
            "1NN   Seen: 90.47%, Unseen: 0.09%, 1NN H: 0.18%\n",
            "FC    Seen: 91.96%, Unseen: 0.02%, FC H: 0.03%\n",
            "unseen=0.0002, seen=0.9196, h=0.0003\n",
            "EP[26/100]************************************************************************************\n",
            "First Seen: 92.44%, Unseen: 0.42%, First H: 0.84%\n",
            "1NN   Seen: 90.53%, Unseen: 0.19%, 1NN H: 0.38%\n",
            "FC    Seen: 91.97%, Unseen: 0.02%, FC H: 0.04%\n",
            "unseen=0.0002, seen=0.9197, h=0.0004\n",
            "EP[27/100]************************************************************************************\n",
            "First Seen: 91.72%, Unseen: 0.70%, First H: 1.39%\n",
            "1NN   Seen: 89.68%, Unseen: 0.31%, 1NN H: 0.62%\n",
            "FC    Seen: 91.83%, Unseen: 0.08%, FC H: 0.16%\n",
            "unseen=0.0008, seen=0.9183, h=0.0016\n",
            "EP[28/100]************************************************************************************\n",
            "First Seen: 91.36%, Unseen: 0.39%, First H: 0.78%\n",
            "1NN   Seen: 89.19%, Unseen: 0.22%, 1NN H: 0.44%\n",
            "FC    Seen: 91.50%, Unseen: 0.02%, FC H: 0.05%\n",
            "unseen=0.0002, seen=0.9150, h=0.0005\n",
            "EP[29/100]************************************************************************************\n",
            "First Seen: 91.47%, Unseen: 0.35%, First H: 0.69%\n",
            "1NN   Seen: 89.62%, Unseen: 0.33%, 1NN H: 0.66%\n",
            "FC    Seen: 91.73%, Unseen: 0.08%, FC H: 0.16%\n",
            "unseen=0.0008, seen=0.9173, h=0.0016\n",
            "EP[30/100]************************************************************************************\n",
            "First Seen: 92.67%, Unseen: 0.31%, First H: 0.61%\n",
            "1NN   Seen: 90.27%, Unseen: 0.27%, 1NN H: 0.53%\n",
            "FC    Seen: 92.35%, Unseen: 0.06%, FC H: 0.13%\n",
            "unseen=0.0006, seen=0.9235, h=0.0013\n",
            "EP[31/100]************************************************************************************\n",
            "First Seen: 92.21%, Unseen: 0.20%, First H: 0.40%\n",
            "1NN   Seen: 90.20%, Unseen: 0.22%, 1NN H: 0.45%\n",
            "FC    Seen: 92.02%, Unseen: 0.02%, FC H: 0.03%\n",
            "unseen=0.0002, seen=0.9202, h=0.0003\n",
            "EP[32/100]************************************************************************************\n",
            "First Seen: 91.65%, Unseen: 1.15%, First H: 2.26%\n",
            "1NN   Seen: 89.61%, Unseen: 0.87%, 1NN H: 1.72%\n",
            "FC    Seen: 91.92%, Unseen: 0.46%, FC H: 0.91%\n",
            "unseen=0.0046, seen=0.9192, h=0.0091\n",
            "EP[33/100]************************************************************************************\n",
            "First Seen: 92.36%, Unseen: 0.26%, First H: 0.53%\n",
            "1NN   Seen: 90.48%, Unseen: 0.16%, 1NN H: 0.32%\n",
            "FC    Seen: 91.94%, Unseen: 0.00%, FC H: 0.00%\n",
            "unseen=0.0000, seen=0.9194, h=0.0000\n",
            "EP[34/100]************************************************************************************\n",
            "First Seen: 92.31%, Unseen: 0.41%, First H: 0.81%\n",
            "1NN   Seen: 90.16%, Unseen: 0.18%, 1NN H: 0.37%\n",
            "FC    Seen: 92.24%, Unseen: 0.02%, FC H: 0.03%\n",
            "unseen=0.0002, seen=0.9224, h=0.0003\n",
            "EP[35/100]************************************************************************************\n",
            "First Seen: 92.27%, Unseen: 0.19%, First H: 0.37%\n",
            "1NN   Seen: 90.49%, Unseen: 0.27%, 1NN H: 0.54%\n",
            "FC    Seen: 92.15%, Unseen: 0.00%, FC H: 0.00%\n",
            "unseen=0.0000, seen=0.9215, h=0.0000\n",
            "EP[36/100]************************************************************************************\n",
            "First Seen: 91.70%, Unseen: 0.21%, First H: 0.42%\n",
            "1NN   Seen: 89.71%, Unseen: 0.32%, 1NN H: 0.64%\n",
            "FC    Seen: 91.93%, Unseen: 0.04%, FC H: 0.08%\n",
            "unseen=0.0004, seen=0.9193, h=0.0008\n",
            "EP[37/100]************************************************************************************\n",
            "First Seen: 92.42%, Unseen: 0.51%, First H: 1.01%\n",
            "1NN   Seen: 90.10%, Unseen: 0.21%, 1NN H: 0.43%\n",
            "FC    Seen: 91.83%, Unseen: 0.03%, FC H: 0.06%\n",
            "unseen=0.0003, seen=0.9183, h=0.0006\n",
            "EP[38/100]************************************************************************************\n",
            "First Seen: 91.89%, Unseen: 0.53%, First H: 1.06%\n",
            "1NN   Seen: 89.68%, Unseen: 0.47%, 1NN H: 0.93%\n",
            "FC    Seen: 91.96%, Unseen: 0.05%, FC H: 0.10%\n",
            "unseen=0.0005, seen=0.9196, h=0.0010\n",
            "EP[39/100]************************************************************************************\n",
            "First Seen: 92.07%, Unseen: 0.21%, First H: 0.43%\n",
            "1NN   Seen: 90.10%, Unseen: 0.23%, 1NN H: 0.46%\n",
            "FC    Seen: 92.17%, Unseen: 0.04%, FC H: 0.08%\n",
            "unseen=0.0004, seen=0.9217, h=0.0008\n",
            "EP[40/100]************************************************************************************\n",
            "First Seen: 91.55%, Unseen: 0.45%, First H: 0.90%\n",
            "1NN   Seen: 89.11%, Unseen: 0.52%, 1NN H: 1.03%\n",
            "FC    Seen: 92.05%, Unseen: 0.08%, FC H: 0.16%\n",
            "unseen=0.0008, seen=0.9205, h=0.0016\n",
            "EP[41/100]************************************************************************************\n",
            "First Seen: 92.16%, Unseen: 0.27%, First H: 0.53%\n",
            "1NN   Seen: 89.95%, Unseen: 0.14%, 1NN H: 0.28%\n",
            "FC    Seen: 92.15%, Unseen: 0.05%, FC H: 0.10%\n",
            "unseen=0.0005, seen=0.9215, h=0.0010\n",
            "EP[42/100]************************************************************************************\n",
            "First Seen: 92.57%, Unseen: 0.30%, First H: 0.59%\n",
            "1NN   Seen: 90.44%, Unseen: 0.39%, 1NN H: 0.77%\n",
            "FC    Seen: 92.17%, Unseen: 0.03%, FC H: 0.06%\n",
            "unseen=0.0003, seen=0.9217, h=0.0006\n",
            "EP[43/100]************************************************************************************\n",
            "First Seen: 92.81%, Unseen: 0.32%, First H: 0.63%\n",
            "1NN   Seen: 90.82%, Unseen: 0.18%, 1NN H: 0.35%\n",
            "FC    Seen: 92.30%, Unseen: 0.02%, FC H: 0.03%\n",
            "unseen=0.0002, seen=0.9230, h=0.0003\n",
            "EP[44/100]************************************************************************************\n",
            "First Seen: 92.53%, Unseen: 0.32%, First H: 0.63%\n",
            "1NN   Seen: 90.47%, Unseen: 0.32%, 1NN H: 0.63%\n",
            "FC    Seen: 92.20%, Unseen: 0.04%, FC H: 0.08%\n",
            "unseen=0.0004, seen=0.9220, h=0.0008\n",
            "EP[45/100]************************************************************************************\n",
            "First Seen: 92.10%, Unseen: 0.27%, First H: 0.54%\n",
            "1NN   Seen: 89.90%, Unseen: 0.22%, 1NN H: 0.43%\n",
            "FC    Seen: 91.82%, Unseen: 0.04%, FC H: 0.08%\n",
            "unseen=0.0004, seen=0.9182, h=0.0008\n",
            "EP[46/100]************************************************************************************\n",
            "First Seen: 91.40%, Unseen: 0.17%, First H: 0.34%\n",
            "1NN   Seen: 89.23%, Unseen: 0.15%, 1NN H: 0.30%\n",
            "FC    Seen: 91.51%, Unseen: 0.01%, FC H: 0.02%\n",
            "unseen=0.0001, seen=0.9151, h=0.0002\n",
            "EP[47/100]************************************************************************************\n",
            "First Seen: 91.94%, Unseen: 0.30%, First H: 0.59%\n",
            "1NN   Seen: 89.61%, Unseen: 0.20%, 1NN H: 0.40%\n",
            "FC    Seen: 91.81%, Unseen: 0.03%, FC H: 0.06%\n",
            "unseen=0.0003, seen=0.9181, h=0.0006\n",
            "EP[48/100]************************************************************************************\n",
            "First Seen: 91.92%, Unseen: 0.48%, First H: 0.95%\n",
            "1NN   Seen: 89.80%, Unseen: 0.63%, 1NN H: 1.25%\n",
            "FC    Seen: 92.05%, Unseen: 0.22%, FC H: 0.45%\n",
            "unseen=0.0022, seen=0.9205, h=0.0045\n",
            "EP[49/100]************************************************************************************\n",
            "First Seen: 92.20%, Unseen: 0.36%, First H: 0.72%\n",
            "1NN   Seen: 90.08%, Unseen: 0.32%, 1NN H: 0.64%\n",
            "FC    Seen: 92.12%, Unseen: 0.02%, FC H: 0.03%\n",
            "unseen=0.0002, seen=0.9212, h=0.0003\n",
            "EP[50/100]************************************************************************************\n",
            "First Seen: 92.36%, Unseen: 1.04%, First H: 2.05%\n",
            "1NN   Seen: 90.15%, Unseen: 0.67%, 1NN H: 1.33%\n",
            "FC    Seen: 92.17%, Unseen: 0.19%, FC H: 0.38%\n",
            "unseen=0.0019, seen=0.9217, h=0.0038\n",
            "EP[51/100]************************************************************************************\n",
            "First Seen: 91.82%, Unseen: 0.53%, First H: 1.05%\n",
            "1NN   Seen: 89.49%, Unseen: 0.32%, 1NN H: 0.64%\n",
            "FC    Seen: 91.86%, Unseen: 0.04%, FC H: 0.08%\n",
            "unseen=0.0004, seen=0.9186, h=0.0008\n",
            "EP[52/100]************************************************************************************\n",
            "First Seen: 92.56%, Unseen: 0.24%, First H: 0.48%\n",
            "1NN   Seen: 90.44%, Unseen: 0.51%, 1NN H: 1.02%\n",
            "FC    Seen: 92.03%, Unseen: 0.02%, FC H: 0.04%\n",
            "unseen=0.0002, seen=0.9203, h=0.0004\n",
            "EP[53/100]************************************************************************************\n",
            "First Seen: 92.73%, Unseen: 0.15%, First H: 0.31%\n",
            "1NN   Seen: 90.55%, Unseen: 0.43%, 1NN H: 0.85%\n",
            "FC    Seen: 92.09%, Unseen: 0.01%, FC H: 0.01%\n",
            "unseen=0.0001, seen=0.9209, h=0.0001\n",
            "EP[54/100]************************************************************************************\n",
            "First Seen: 91.76%, Unseen: 0.32%, First H: 0.64%\n",
            "1NN   Seen: 89.63%, Unseen: 0.33%, 1NN H: 0.66%\n",
            "FC    Seen: 91.77%, Unseen: 0.03%, FC H: 0.06%\n",
            "unseen=0.0003, seen=0.9177, h=0.0006\n",
            "EP[55/100]************************************************************************************\n",
            "First Seen: 92.62%, Unseen: 0.29%, First H: 0.58%\n",
            "1NN   Seen: 90.15%, Unseen: 0.51%, 1NN H: 1.02%\n",
            "FC    Seen: 92.13%, Unseen: 0.00%, FC H: 0.00%\n",
            "unseen=0.0000, seen=0.9213, h=0.0000\n",
            "EP[56/100]************************************************************************************\n",
            "First Seen: 92.40%, Unseen: 0.31%, First H: 0.62%\n",
            "1NN   Seen: 90.61%, Unseen: 0.29%, 1NN H: 0.57%\n",
            "FC    Seen: 92.08%, Unseen: 0.03%, FC H: 0.07%\n",
            "unseen=0.0003, seen=0.9208, h=0.0007\n",
            "EP[57/100]************************************************************************************\n",
            "First Seen: 92.60%, Unseen: 0.28%, First H: 0.55%\n",
            "1NN   Seen: 90.14%, Unseen: 0.43%, 1NN H: 0.85%\n",
            "FC    Seen: 92.36%, Unseen: 0.07%, FC H: 0.15%\n",
            "unseen=0.0007, seen=0.9236, h=0.0015\n",
            "EP[58/100]************************************************************************************\n",
            "First Seen: 92.59%, Unseen: 0.23%, First H: 0.47%\n",
            "1NN   Seen: 90.69%, Unseen: 0.35%, 1NN H: 0.70%\n",
            "FC    Seen: 91.92%, Unseen: 0.02%, FC H: 0.03%\n",
            "unseen=0.0002, seen=0.9192, h=0.0003\n",
            "EP[59/100]************************************************************************************\n",
            "First Seen: 92.20%, Unseen: 0.51%, First H: 1.02%\n",
            "1NN   Seen: 89.85%, Unseen: 0.28%, 1NN H: 0.55%\n",
            "FC    Seen: 92.24%, Unseen: 0.05%, FC H: 0.10%\n",
            "unseen=0.0005, seen=0.9224, h=0.0010\n",
            "EP[60/100]************************************************************************************\n",
            "First Seen: 91.43%, Unseen: 0.34%, First H: 0.67%\n",
            "1NN   Seen: 89.18%, Unseen: 0.50%, 1NN H: 0.99%\n",
            "FC    Seen: 91.81%, Unseen: 0.11%, FC H: 0.22%\n",
            "unseen=0.0011, seen=0.9181, h=0.0022\n",
            "EP[61/100]************************************************************************************\n",
            "First Seen: 92.72%, Unseen: 0.30%, First H: 0.60%\n",
            "1NN   Seen: 90.71%, Unseen: 0.41%, 1NN H: 0.82%\n",
            "FC    Seen: 92.25%, Unseen: 0.05%, FC H: 0.10%\n",
            "unseen=0.0005, seen=0.9225, h=0.0010\n",
            "EP[62/100]************************************************************************************\n",
            "First Seen: 92.35%, Unseen: 0.48%, First H: 0.95%\n",
            "1NN   Seen: 90.16%, Unseen: 0.22%, 1NN H: 0.43%\n",
            "FC    Seen: 92.10%, Unseen: 0.02%, FC H: 0.03%\n",
            "unseen=0.0002, seen=0.9210, h=0.0003\n",
            "EP[63/100]************************************************************************************\n",
            "First Seen: 92.46%, Unseen: 0.28%, First H: 0.56%\n",
            "1NN   Seen: 90.60%, Unseen: 0.28%, 1NN H: 0.56%\n",
            "FC    Seen: 92.19%, Unseen: 0.03%, FC H: 0.05%\n",
            "unseen=0.0003, seen=0.9219, h=0.0005\n",
            "EP[64/100]************************************************************************************\n",
            "First Seen: 92.40%, Unseen: 0.12%, First H: 0.25%\n",
            "1NN   Seen: 90.13%, Unseen: 0.30%, 1NN H: 0.59%\n",
            "FC    Seen: 92.38%, Unseen: 0.02%, FC H: 0.05%\n",
            "unseen=0.0002, seen=0.9238, h=0.0005\n",
            "EP[65/100]************************************************************************************\n",
            "First Seen: 90.29%, Unseen: 0.38%, First H: 0.75%\n",
            "1NN   Seen: 89.15%, Unseen: 0.66%, 1NN H: 1.31%\n",
            "FC    Seen: 91.41%, Unseen: 0.03%, FC H: 0.06%\n",
            "unseen=0.0003, seen=0.9141, h=0.0006\n",
            "EP[66/100]************************************************************************************\n",
            "First Seen: 91.63%, Unseen: 0.29%, First H: 0.57%\n",
            "1NN   Seen: 89.41%, Unseen: 0.53%, 1NN H: 1.05%\n",
            "FC    Seen: 91.80%, Unseen: 0.11%, FC H: 0.23%\n",
            "unseen=0.0011, seen=0.9180, h=0.0023\n",
            "EP[67/100]************************************************************************************\n",
            "First Seen: 91.51%, Unseen: 0.77%, First H: 1.53%\n",
            "1NN   Seen: 89.36%, Unseen: 1.19%, 1NN H: 2.35%\n",
            "FC    Seen: 92.00%, Unseen: 0.40%, FC H: 0.80%\n",
            "unseen=0.0040, seen=0.9200, h=0.0080\n",
            "EP[68/100]************************************************************************************\n",
            "First Seen: 92.09%, Unseen: 0.23%, First H: 0.47%\n",
            "1NN   Seen: 89.70%, Unseen: 0.41%, 1NN H: 0.83%\n",
            "FC    Seen: 92.03%, Unseen: 0.01%, FC H: 0.02%\n",
            "unseen=0.0001, seen=0.9203, h=0.0002\n",
            "EP[69/100]************************************************************************************\n",
            "First Seen: 91.01%, Unseen: 0.46%, First H: 0.91%\n",
            "1NN   Seen: 89.06%, Unseen: 0.34%, 1NN H: 0.69%\n",
            "FC    Seen: 91.66%, Unseen: 0.02%, FC H: 0.03%\n",
            "unseen=0.0002, seen=0.9166, h=0.0003\n",
            "EP[70/100]************************************************************************************\n",
            "First Seen: 91.57%, Unseen: 0.28%, First H: 0.57%\n",
            "1NN   Seen: 89.47%, Unseen: 0.29%, 1NN H: 0.57%\n",
            "FC    Seen: 91.81%, Unseen: 0.04%, FC H: 0.07%\n",
            "unseen=0.0004, seen=0.9181, h=0.0007\n",
            "EP[71/100]************************************************************************************\n",
            "First Seen: 91.28%, Unseen: 0.28%, First H: 0.56%\n",
            "1NN   Seen: 89.15%, Unseen: 0.61%, 1NN H: 1.21%\n",
            "FC    Seen: 91.64%, Unseen: 0.03%, FC H: 0.05%\n",
            "unseen=0.0003, seen=0.9164, h=0.0005\n",
            "EP[72/100]************************************************************************************\n",
            "First Seen: 92.25%, Unseen: 0.25%, First H: 0.50%\n",
            "1NN   Seen: 89.96%, Unseen: 0.54%, 1NN H: 1.08%\n",
            "FC    Seen: 91.93%, Unseen: 0.03%, FC H: 0.06%\n",
            "unseen=0.0003, seen=0.9193, h=0.0006\n",
            "EP[73/100]************************************************************************************\n",
            "First Seen: 91.93%, Unseen: 0.24%, First H: 0.47%\n",
            "1NN   Seen: 89.79%, Unseen: 0.32%, 1NN H: 0.63%\n",
            "FC    Seen: 92.19%, Unseen: 0.04%, FC H: 0.08%\n",
            "unseen=0.0004, seen=0.9219, h=0.0008\n",
            "EP[74/100]************************************************************************************\n",
            "First Seen: 91.14%, Unseen: 0.28%, First H: 0.56%\n",
            "1NN   Seen: 89.09%, Unseen: 0.37%, 1NN H: 0.73%\n",
            "FC    Seen: 91.53%, Unseen: 0.03%, FC H: 0.06%\n",
            "unseen=0.0003, seen=0.9153, h=0.0006\n",
            "EP[75/100]************************************************************************************\n",
            "First Seen: 92.08%, Unseen: 0.28%, First H: 0.55%\n",
            "1NN   Seen: 89.77%, Unseen: 0.35%, 1NN H: 0.71%\n",
            "FC    Seen: 92.26%, Unseen: 0.01%, FC H: 0.01%\n",
            "unseen=0.0001, seen=0.9226, h=0.0001\n",
            "EP[76/100]************************************************************************************\n",
            "First Seen: 91.24%, Unseen: 0.95%, First H: 1.88%\n",
            "1NN   Seen: 89.50%, Unseen: 0.75%, 1NN H: 1.48%\n",
            "FC    Seen: 91.73%, Unseen: 0.23%, FC H: 0.46%\n",
            "unseen=0.0023, seen=0.9173, h=0.0046\n",
            "EP[77/100]************************************************************************************\n",
            "First Seen: 92.39%, Unseen: 0.50%, First H: 1.00%\n",
            "1NN   Seen: 90.02%, Unseen: 0.31%, 1NN H: 0.62%\n",
            "FC    Seen: 92.15%, Unseen: 0.10%, FC H: 0.19%\n",
            "unseen=0.0010, seen=0.9215, h=0.0019\n",
            "EP[78/100]************************************************************************************\n",
            "First Seen: 91.92%, Unseen: 0.62%, First H: 1.23%\n",
            "1NN   Seen: 89.43%, Unseen: 0.78%, 1NN H: 1.54%\n",
            "FC    Seen: 91.52%, Unseen: 0.21%, FC H: 0.41%\n",
            "unseen=0.0021, seen=0.9152, h=0.0041\n",
            "EP[79/100]************************************************************************************\n",
            "First Seen: 91.58%, Unseen: 0.23%, First H: 0.46%\n",
            "1NN   Seen: 89.57%, Unseen: 0.33%, 1NN H: 0.65%\n",
            "FC    Seen: 91.80%, Unseen: 0.00%, FC H: 0.00%\n",
            "unseen=0.0000, seen=0.9180, h=0.0000\n",
            "EP[80/100]************************************************************************************\n",
            "First Seen: 91.91%, Unseen: 0.44%, First H: 0.87%\n",
            "1NN   Seen: 89.81%, Unseen: 0.66%, 1NN H: 1.31%\n",
            "FC    Seen: 91.91%, Unseen: 0.10%, FC H: 0.19%\n",
            "unseen=0.0010, seen=0.9191, h=0.0019\n",
            "EP[81/100]************************************************************************************\n",
            "First Seen: 92.09%, Unseen: 0.26%, First H: 0.51%\n",
            "1NN   Seen: 89.94%, Unseen: 0.19%, 1NN H: 0.38%\n",
            "FC    Seen: 91.95%, Unseen: 0.04%, FC H: 0.08%\n",
            "unseen=0.0004, seen=0.9195, h=0.0008\n",
            "EP[82/100]************************************************************************************\n",
            "First Seen: 91.95%, Unseen: 0.17%, First H: 0.35%\n",
            "1NN   Seen: 89.76%, Unseen: 0.41%, 1NN H: 0.82%\n",
            "FC    Seen: 92.04%, Unseen: 0.03%, FC H: 0.06%\n",
            "unseen=0.0003, seen=0.9204, h=0.0006\n",
            "EP[83/100]************************************************************************************\n",
            "First Seen: 91.87%, Unseen: 0.26%, First H: 0.51%\n",
            "1NN   Seen: 89.65%, Unseen: 0.32%, 1NN H: 0.63%\n",
            "FC    Seen: 91.99%, Unseen: 0.05%, FC H: 0.10%\n",
            "unseen=0.0005, seen=0.9199, h=0.0010\n",
            "EP[84/100]************************************************************************************\n",
            "First Seen: 92.35%, Unseen: 0.27%, First H: 0.54%\n",
            "1NN   Seen: 90.32%, Unseen: 0.36%, 1NN H: 0.71%\n",
            "FC    Seen: 92.26%, Unseen: 0.01%, FC H: 0.01%\n",
            "unseen=0.0001, seen=0.9226, h=0.0001\n",
            "EP[85/100]************************************************************************************\n",
            "First Seen: 91.95%, Unseen: 0.35%, First H: 0.70%\n",
            "1NN   Seen: 90.09%, Unseen: 0.36%, 1NN H: 0.72%\n",
            "FC    Seen: 92.24%, Unseen: 0.01%, FC H: 0.02%\n",
            "unseen=0.0001, seen=0.9224, h=0.0002\n",
            "EP[86/100]************************************************************************************\n",
            "First Seen: 91.98%, Unseen: 0.37%, First H: 0.75%\n",
            "1NN   Seen: 89.58%, Unseen: 0.38%, 1NN H: 0.75%\n",
            "FC    Seen: 92.01%, Unseen: 0.05%, FC H: 0.10%\n",
            "unseen=0.0005, seen=0.9201, h=0.0010\n",
            "EP[87/100]************************************************************************************\n",
            "First Seen: 91.78%, Unseen: 0.25%, First H: 0.49%\n",
            "1NN   Seen: 89.68%, Unseen: 0.31%, 1NN H: 0.62%\n",
            "FC    Seen: 91.54%, Unseen: 0.00%, FC H: 0.00%\n",
            "unseen=0.0000, seen=0.9154, h=0.0000\n",
            "EP[88/100]************************************************************************************\n",
            "First Seen: 92.23%, Unseen: 0.21%, First H: 0.42%\n",
            "1NN   Seen: 89.96%, Unseen: 0.34%, 1NN H: 0.69%\n",
            "FC    Seen: 91.89%, Unseen: 0.02%, FC H: 0.03%\n",
            "unseen=0.0002, seen=0.9189, h=0.0003\n",
            "EP[89/100]************************************************************************************\n",
            "First Seen: 91.17%, Unseen: 0.20%, First H: 0.39%\n",
            "1NN   Seen: 89.19%, Unseen: 0.15%, 1NN H: 0.29%\n",
            "FC    Seen: 91.73%, Unseen: 0.02%, FC H: 0.05%\n",
            "unseen=0.0002, seen=0.9173, h=0.0005\n",
            "EP[90/100]************************************************************************************\n",
            "First Seen: 92.08%, Unseen: 0.25%, First H: 0.51%\n",
            "1NN   Seen: 90.52%, Unseen: 0.61%, 1NN H: 1.21%\n",
            "FC    Seen: 92.01%, Unseen: 0.03%, FC H: 0.05%\n",
            "unseen=0.0003, seen=0.9201, h=0.0005\n",
            "EP[91/100]************************************************************************************\n",
            "First Seen: 91.98%, Unseen: 0.25%, First H: 0.50%\n",
            "1NN   Seen: 90.11%, Unseen: 0.29%, 1NN H: 0.58%\n",
            "FC    Seen: 92.03%, Unseen: 0.06%, FC H: 0.11%\n",
            "unseen=0.0006, seen=0.9203, h=0.0011\n",
            "EP[92/100]************************************************************************************\n",
            "First Seen: 92.83%, Unseen: 0.18%, First H: 0.35%\n",
            "1NN   Seen: 90.92%, Unseen: 0.31%, 1NN H: 0.61%\n",
            "FC    Seen: 92.27%, Unseen: 0.02%, FC H: 0.03%\n",
            "unseen=0.0002, seen=0.9227, h=0.0003\n",
            "EP[93/100]************************************************************************************\n",
            "First Seen: 92.36%, Unseen: 0.42%, First H: 0.84%\n",
            "1NN   Seen: 90.14%, Unseen: 0.49%, 1NN H: 0.98%\n",
            "FC    Seen: 92.14%, Unseen: 0.05%, FC H: 0.10%\n",
            "unseen=0.0005, seen=0.9214, h=0.0010\n",
            "EP[94/100]************************************************************************************\n",
            "First Seen: 92.51%, Unseen: 0.34%, First H: 0.68%\n",
            "1NN   Seen: 90.51%, Unseen: 0.34%, 1NN H: 0.68%\n",
            "FC    Seen: 92.08%, Unseen: 0.04%, FC H: 0.08%\n",
            "unseen=0.0004, seen=0.9208, h=0.0008\n",
            "EP[95/100]************************************************************************************\n",
            "First Seen: 92.50%, Unseen: 0.43%, First H: 0.86%\n",
            "1NN   Seen: 90.19%, Unseen: 0.18%, 1NN H: 0.37%\n",
            "FC    Seen: 92.16%, Unseen: 0.00%, FC H: 0.00%\n",
            "unseen=0.0000, seen=0.9216, h=0.0000\n",
            "EP[96/100]************************************************************************************\n",
            "First Seen: 90.15%, Unseen: 0.60%, First H: 1.18%\n",
            "1NN   Seen: 88.61%, Unseen: 0.66%, 1NN H: 1.32%\n",
            "FC    Seen: 91.32%, Unseen: 0.18%, FC H: 0.37%\n",
            "unseen=0.0018, seen=0.9132, h=0.0037\n",
            "EP[97/100]************************************************************************************\n",
            "First Seen: 91.81%, Unseen: 0.62%, First H: 1.24%\n",
            "1NN   Seen: 89.65%, Unseen: 0.68%, 1NN H: 1.35%\n",
            "FC    Seen: 91.84%, Unseen: 0.16%, FC H: 0.32%\n",
            "unseen=0.0016, seen=0.9184, h=0.0032\n",
            "EP[98/100]************************************************************************************\n",
            "First Seen: 91.42%, Unseen: 0.44%, First H: 0.87%\n",
            "1NN   Seen: 89.30%, Unseen: 0.52%, 1NN H: 1.04%\n",
            "FC    Seen: 91.96%, Unseen: 0.04%, FC H: 0.09%\n",
            "unseen=0.0004, seen=0.9196, h=0.0009\n",
            "EP[99/100]************************************************************************************\n",
            "First Seen: 92.49%, Unseen: 0.14%, First H: 0.28%\n",
            "1NN   Seen: 90.63%, Unseen: 0.34%, 1NN H: 0.69%\n",
            "FC    Seen: 91.83%, Unseen: 0.00%, FC H: 0.00%\n",
            "unseen=0.0000, seen=0.9183, h=0.0000\n",
            "End run!!!\n",
            "Time Elapsed: 5248.298869848251\n",
            "2020-09-20 13:19:54\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "hRa_cCWxwU0r",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        ""
      ],
      "execution_count": null,
      "outputs": []
    }
  ]
}